El Machine Learning nos permitirá utilizar Redes Neuronales para que un coche Arduino conduzca sólo evitando obstáculos.
En el artículo anterior, creamos una red neuronal desde cero en Python. En este artículo mejoraremos esa red y copiaremos sus pesos a una red con propagación hacia adelante en Arduino que permitirá que el coche robot conduzca sólo sin chocar.
La Nueva Red Neuronal
Por simplificar el modelo de aprendizaje, en el post anterior teníamos una red de tres capas con 2 neuronas de entrada 3 ocultas y 2 de salida: giro y dirección. Para este ejercicio haremos que la red neuronal tenga 4 salidas: una para cada motor. Además las salidas serán entre 0 y 1 (apagar o encender motor). También cambiaremos las entradas para que todas comprendan valores entre -1 y 1 y sean acordes a nuestra función tangente hiperbólica. Aquí vemos los cambios en esta tabla:
Entrada: Sensor Distancia | Entrada: Posición Obstáculo | Salida: Motor 1 | Salida: Motor 2 | Salida: Motor 3 | Salida: Motor 4 |
---|---|---|---|---|---|
-1 | 0 | 1 | 0 | 0 | 1 |
-1 | 1 | 1 | 0 | 0 | 1 |
-1 | -1 | 1 | 0 | 0 | 1 |
0 | -1 | 1 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 0 | 1 |
0 | 0 | 1 | 0 | 0 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
1 | -1 | 0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 0 |
Siendo el valor de los motores 1 y 0:
Acción | Motor 1 | Motor 2 | Motor 3 | Motor 4 |
---|---|---|---|---|
Avanzar | 1 | 0 | 0 | 1 |
Retroceder | 0 | 1 | 1 | 0 |
Giro Derecha | 0 | 1 | 0 | 1 |
Giro Izquierda | 1 | 0 | 1 | 0 |
Para instanciar nuestra red ahora usaremos este código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# Red Coche para Evitar obstáculos nn = NeuralNetwork([2,3,4],activation ='tanh') X = np.array([[-1, 0], # sin obstaculos [-1, 1], # sin obstaculos [-1, -1], # sin obstaculos [0, -1], # obstaculo detectado a derecha [0,1], # obstaculo a izq [0,0], # obstaculo centro [1,1], # demasiado cerca a derecha [1,-1], # demasiado cerca a izq [1,0] # demasiado cerca centro ]) # las salidas 'y' se corresponden con encender (o no) los motores y = np.array([[1,0,0,1], # avanzar [1,0,0,1], # avanzar [1,0,0,1], # avanzar [0,1,0,1], # giro derecha [1,0,1,0], # giro izquierda (cambie izq y derecha) [1,0,0,1], # avanzar [0,1,1,0], # retroceder [0,1,1,0], # retroceder [0,1,1,0] # retroceder ]) nn.fit(X, y, learning_rate=0.03,epochs=40001) def valNN(x): return (int)(abs(round(x))) index=0 for e in X: prediccion = nn.predict(e) print("X:",e,"esperado:",y[index],"obtenido:", valNN(prediccion[0]),valNN(prediccion[1]),valNN(prediccion[2]),valNN(prediccion[3])) index=index+1 |
Aquí podemos ver el código Python Completo modificado de la Jupyter Notebook. Y también vemos la gráfica del coste, que disminuye a medida que se entrena tras 40.000 iteraciones.
¿¿No es impresionante cómo con apenas 9 datos de entrada podemos enseñar a un robot a conducir??
El coche Arduino
En mi caso es un coche Arduino Elegoo Uno V3 de 4 motores. Si eres Maker, te resultará fácil construir el tuyo o puede que ya tengas uno en casa para programarlo. El coche puede ser cualquier otro, de hecho podría ser de 2 motores y modificando apenas la red funcionaría. En caso de querer construirlo tu mismo explicaré brevemente los requerimientos:
Necesitaremos:
- Una placa Arduino Uno y una placa de expansión de IO
- o puede ser una placa Arduino Mega
- El controlador de motor L298N
- 4 motores DC (o podrían ser 2) y sus ruedas
- Servo Motor SG90
- Sensor Ultrasónico
- Baterias para alimentar los motores (y la placa obviamente!)
- Chasis para el coche
- Cables!
Circuito del coche
No entraré en detalle, ya que va más allá de este tutorial (si a muchos lectores les interesa, podría ampliar el artículo en el futuro) pero básicamente tenemos el siguiente circuito (ignorar el bluetooth y los sensores infrarrojos):
Montar el coche
Utilizaremos un Servo en la parte delantera del coche que moverá al sensor de distancia de izquierda a derecha, a modo de radar, para detectar obstáculos.
Más allá de eso… es un coche! pondremos las 4 ruedas y las placas Arduino encima del chasis. (El objetivo de este artículo es enseñar a programar una red neuronal en la IDE de Arduino)
Este es el video tutorial oficial de ensamblaje de Elegoo de este coche.
Así nos quedará montado… ta taáan:
Copiar la red neuronal
Una vez obtenida la red neuronal Python, haremos copiar y pegar de la matriz de pesos en el código Arduino (reemplazaremos las lineas 23 y 24):
El código Arduino
El código Arduino controlará el servo motor con el sensor de distancia que se moverá de izquierda a derecha y nos proveerá las entradas de la red: Distancia y Dirección(ó giro).
El resto, lo hará la red neuronal! En realidad, la red ya “aprendió” (en Python) es decir, sólo hará multiplicaciones y sumas de los pesos para obtener salidas. Realizará el camino forward propagation. Y las salidas controlarán directamente los 4 motores.
Hay código adicional para darle ciclos de tiempo a las ruedas a moverse (variable accionEnCurso) y dar más o menos potencia a los motores al cambiar de dirección. Son relativamente pocas líneas de código y logramos que la red neuronal conduzca el coche!
Nota: Para el movimiento del Servo motor se utiliza una librería “Servo” estándard.
Aquí vemos el código Arduino completo. Tal vez la parte más interesante sea la función conducir().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
#include <Servo.h> //servo library Servo myservo; // create servo object to control servo int Echo = A4; int Trig = A5; #define ENA 5 #define ENB 6 #define IN1 7 #define IN2 8 #define IN3 9 #define IN4 11 /****************************************************************** Network Configuration ******************************************************************/ const int InputNodes = 3; // incluye neurona de BIAS const int HiddenNodes = 4; //incluye neurona de BIAS const int OutputNodes = 4; int i, j; double Accum; double Hidden[HiddenNodes]; double Output[OutputNodes]; float HiddenWeights[3][4] = {{1.8991509504079183, -0.4769472541445052, -0.6483690220539764, -0.38609165249078925}, {-0.2818610915467527, 4.040695699457223, 3.2291858058243843, -2.894301104732614}, {0.3340650864625773, -1.4016114422346901, 1.3580053902963762, -0.981415976256285}}; float OutputWeights[4][4] = {{1.136072297461121, 1.54602394937381, 1.6194612259569254, 1.8819066696635067}, {-1.546966506764457, 1.3951930739494225, 0.19393826092602756, 0.30992504138547006}, {-0.7755982417649826, 0.9390808625728915, 2.0862510744685485, -1.1229484266101883}, {-1.2357090352280826, 0.8583930286034466, 0.724702079881947, 0.9762852709700459}}; /****************************************************************** End Network Configuration ******************************************************************/ void stop() { digitalWrite(ENA, LOW); //Desactivamos los motores digitalWrite(ENB, LOW); //Desactivamos los motores Serial.println("Stop!"); } //Medir distancia en Centimetros int Distance_test() { digitalWrite(Trig, LOW); delayMicroseconds(2); digitalWrite(Trig, HIGH); delayMicroseconds(20); digitalWrite(Trig, LOW); float Fdistance = pulseIn(Echo, HIGH); Fdistance= Fdistance / 58; return (int)Fdistance; } void setup() { myservo.attach(3); // attach servo on pin 3 to servo object Serial.begin(9600); pinMode(Echo, INPUT); pinMode(Trig, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT); stop(); myservo.write(90); //posicion inicial en el centro delay(500); } unsigned long previousMillis = 0; // para medir ciclos de tiempo const long interval = 25; // intervalos cada x milisegundos int grados_servo = 90; // posicion del servo que mueve el sensor ultrasonico bool clockwise = true; // sentido de giro del servo const long ANGULO_MIN = 30; const long ANGULO_MAX = 150; double ditanciaMaxima = 50.0; // distancia de lejania desde la que empieza a actuar la NN int incrementos = 9; // incrementos por ciclo de posicion del servo int accionEnCurso = 1; // cantidad de ciclos ejecutando una accion int multiplicador = 1000/interval; // multiplica la cant de ciclos para dar tiempo a que el coche pueda girar const int SPEED = 100; // velocidad del coche de las 4 ruedas a la vez. void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; /****************************************************************** MANEJAR GIRO de SERVO ******************************************************************/ if(grados_servo<=ANGULO_MIN || grados_servo>=ANGULO_MAX){ clockwise=!clockwise; // cambio de sentido grados_servo = constrain(grados_servo, ANGULO_MIN, ANGULO_MAX); } if(clockwise) grados_servo=grados_servo+incrementos; else grados_servo=grados_servo-incrementos; if(accionEnCurso>0){ accionEnCurso=accionEnCurso-1; }else{ /****************************************************************** LLAMAMOS a la FUNCION DE CONDUCCION ******************************************************************/ conducir(); } myservo.write(grados_servo); } } //USA LA RED NEURONAL YA ENTRENADA void conducir() { double TestInput[] = {0, 0,0}; double entrada1=0,entrada2=0; /****************************************************************** OBTENER DISTANCIA DEL SENSOR ******************************************************************/ double distance = double(Distance_test()); distance= double(constrain(distance, 0.0, ditanciaMaxima)); entrada1= ((-2.0/ditanciaMaxima)*double(distance))+1.0; //uso una funcion lineal para obtener cercania accionEnCurso = ((entrada1 +1) * multiplicador)+1; // si esta muy cerca del obstaculo, necestia mas tiempo de reaccion /****************************************************************** OBTENER DIRECCION SEGUN ANGULO DEL SERVO ******************************************************************/ entrada2 = map(grados_servo, ANGULO_MIN, ANGULO_MAX, -100, 100); entrada2 = double(constrain(entrada2, -100.00, 100.00)); /****************************************************************** LLAMAMOS A LA RED FEEDFORWARD CON LAS ENTRADAS ******************************************************************/ Serial.print("Entrada1:"); Serial.println(entrada1); Serial.print("Entrada2:"); Serial.println(entrada2/100.0); TestInput[0] = 1.0;//BIAS UNIT TestInput[1] = entrada1; TestInput[2] = entrada2/100.0; InputToOutput(TestInput[0], TestInput[1], TestInput[2]); //INPUT to ANN to obtain OUTPUT int out1 = round(abs(Output[0])); int out2 = round(abs(Output[1])); int out3 = round(abs(Output[2])); int out4 = round(abs(Output[3])); Serial.print("Salida1:"); Serial.println(out1); Serial.print("Salida2:"); Serial.println(out2); Serial.println(Output[1]); Serial.print("Salida3:"); Serial.println(out3); Serial.print("Salida4:"); Serial.println(out4); /****************************************************************** IMPULSAR MOTORES CON LA SALIDA DE LA RED ******************************************************************/ int carSpeed = SPEED; //hacia adelante o atras if((out1+out3)==2 || (out2+out4)==2){ // si es giro, necesita doble fuerza los motores carSpeed = SPEED * 2; } analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, out1 * HIGH); digitalWrite(IN2, out2 * HIGH); digitalWrite(IN3, out3 * HIGH); digitalWrite(IN4, out4 * HIGH); } void InputToOutput(double In1, double In2, double In3) { double TestInput[] = {0, 0,0}; TestInput[0] = In1; TestInput[1] = In2; TestInput[2] = In3; /****************************************************************** Calcular las activaciones en las capas ocultas ******************************************************************/ for ( i = 0 ; i < HiddenNodes ; i++ ) { Accum = 0;//HiddenWeights[InputNodes][i] ; for ( j = 0 ; j < InputNodes ; j++ ) { Accum += TestInput[j] * HiddenWeights[j][i] ; } //Hidden[i] = 1.0 / (1.0 + exp(-Accum)) ; //Sigmoid Hidden[i] = tanh(Accum) ; //tanh } /****************************************************************** Calcular activacion y error en la capa de Salida ******************************************************************/ for ( i = 0 ; i < OutputNodes ; i++ ) { Accum = 0;//OutputWeights[HiddenNodes][i]; for ( j = 0 ; j < HiddenNodes ; j++ ) { Accum += Hidden[j] * OutputWeights[j][i] ; } Output[i] = tanh(Accum) ;//tanh } } |
El Coche en Acción!
Conecta tu coche, sube el código y ¡pruébalo!
Veamos un video del coche funcionando con su propia inteligencia artificial en el planeta tierra.
Conclusión
Aplicamos Machine Learning y sus redes neuronales a un objeto del mundo real y vimos cómo funciona, haciendo que el coche evite obstáculos y tome las decisiones por sí mismo, sin haberle dado instrucciones ni código explícito.
Puedes leer aquí sobre Redes Neuronales a lo largo de la historia
Mejoras a Futuro
Tengamos en cuenta que estamos teniendo como entradas los datos proporcionados por un sólo sensor de distancia y un servo motor que nos indica si está a izquierda o derecha. Podríamos tener más sensores de distancia, infrarrojos, medir velocidad, luz, sonido… en fin. Si tuviéramos que programar “manualmente” ese algoritmo, tendría una complejidad enorme y sería muy difícil de mantener o modificar. En cambio, hacer que una red neuronal aprenda sería muy sencillo. Tan sólo agregaríamos features (columnas) a nuestro código y volveríamos a entrenar nuevamente la red. Voila!. Copiar y pegar los pesos obtenidos en Arduino, y nuestro coche tendría la inteligencia de manejarse por sí mismo nuevamente.
Suscripción al Blog
Puedes suscribirte al Blog y ser el primero en recibir los artículos cada 15 días.
Puedes hacer más ejercicios de Aprendizaje Automático en Python en nuestra categoría d Ejercicios paso a paso
Recursos
- Artículo anterior, donde se explica con mayor detalle cómo se crea la Red Neuronal
- Descarga el código Python con la nueva Red Neuronal
- Descarga el código Arduino
- Si quieres comprar el mismo coche Arduino que yo, click aqui: ELEGOO UNO Proyecto Kit de Coche Robot Inteligente V3.0. Te recuerdo que puedes construir tu propio coche Arduino si te das maña y utilizar este código. De hecho puede funcionar con un coche de 2 motores modificando las salidas de la red, en vez de tener 4, tener 2.
- Aquí puedes ver a otro Maker que hizo un coche Arduino con Red Neuronal que escapa de la luz.
Hola, muchas gracias por el interesante artículo y la cantidad de detalle que aportas, pero perdona mi ignorancia. Acabo de iniciarme en estos temas. Lo que no acabo de entender es por qué utilizas una red neuronal y no un sistema de reglas simples tipo if pasa esto then esto
Hola Pedro, gracias por leer el blog y comentar. Pues justamente de eso se trata: de no tener que indicar la instrucciones una por una. El Aprendizaje automático evita que el programador tenga que dictar todas las condiciones “if” y hace que el algoritmo seleccionado tome las decisiones (sean predicciones o clasificacion, etc). Imagina que además de escribir el código par controlar las ruedas del coche y evitar obstáculos, tuviéramos que controlar más sensores: de velocidad, posición, luz, sonido, etc. Eso serían cada vez más y más lineas de código a programar “a mano” y difíciles de mantener en el futuro, y propensas a bugs. En cambio con una -o varias- redes neuronales, podemos hacer que el coche aprenda sólo a controlarse y ajustar su comportamiento, en base a las entrada que obtiene de los sensores.
ok, entendido Na8, gracias por tu respuesta.
Otra duda más. ¿Por qué programas tu propia red neuronal en lugar de utilizar un módulo como scikit-learn?
Entiendo que es más un ejercicio que otra cosa porque el resultado debería ser similar si utilizamos scikit-learn
Si exacto, es más que nada para explicar cómo funciona internamente una red neuronal y el backpropagation. En la práctica conviene utilizar -por ejemplo- keras y tesorflow (de Google). Si aún no leíste, puedes ver este artículo anterior a modo ilustrativo:Una sencilla red Neuronal con Keras
Nuevamente gracias por comentar! Espero que sigas leyendo los nuevos artículos!
Gracias!
Hola, yo tengo el Elegoo V1 y le subí tu programación pero el carro no anda hacia adelante, solo hacia un lado cuando detecta un obstáculo a cierta distancia, que me recomendarías o que solución me darías?
Hola Cristian, gracias por escribirme! Mira, deberías probar variando algunos de los parámetros. PERO casi apostaría que debes aumentar el valor de SPEED que está en 100, prueba con 150 ó 200. Esto es para darle más fuerza, y desconozco si la versión V1 tiene distintas potencias en los motores.
Buenas tardes Cristian, me pasa igual que al compañero anterior. Estoy trasteando e intentando entender el programa,, pero al cargarlo al coche, no avanza por sí solo. Al acercarle obstáculos sí que se mueve, pero por sí solo, no empieza a andar. ¿Habría que modificar algún parámetro de la función conducir? Tengo el V2, ¿podrías ayudarnos? Gracias y enhorabuena por tu gran trabajo, es muy interesante.
Hola Jose, fíjate si puedes modificar el valor de la variable SPEED como le indicaba a Cristian.
En mi código tiene un valor de 100, pero prueba a darle un valor mayor, (el valor puede ir de 0 a 255).
Prueba por ejemplo con 200, para comprobar que avanza.
Si lo haces te pido que escribas luego y me informes si se arregla o no. Gracias!, saludos
Hola Juan Ignacio, acabo de probar con 200 y hace lo mismo pero más rápido. Esquiva bien el obstáculo pero es el obstáculo el que yo muevo hacia el coche, sólo me falta que sea el coche el que avance hacia adelante. Creo que el valor de 100 está bien, debe ser otro parámetro… seguiré investigando. Si sospechas de otra parte que pueda modificar, por favor, avísame. Gracias por tu ayuda!!
Jose, Una pregunta por confirmar: Entiendo que el coche está parado sin moverse, pero que si le acercas un obstáculo, reacciona y hace la maniobra de esquivar.
¿Puedes levantar en el aire el coche y confirmar que las ruedas no giran?
¿o es que giran en direcciones opuestas y por eso queda frenado?
Hola de nuevo Juan. Acabo de levantarlo del suelo y las ruedas están paradas cuando no hay obstáculo. No se produce contradicción entre ellas al empujar, de hecho, se gira muy rápido al acercar rápido un obstáculo. Cuando lo acerco a los obstáculos o le acerco la mano, se ponen a girar las ruedas de un lado o las del otro y esquiva correctamente, es decir, no llego a poder tocarlo porque se gira o da la vuelta (lento o rápido). Lo que no hace es girar las cuatro ruedas en el mismo sentido y avanzar de frente en línea recta, sólo giran para esquivar el obstáculo (le acerco la mano, lo levanto del suelo y acerco a la pared…) las cuatro ruedas están paradas y para esquivar, giran de un lado haciendo un giro de 90 o 180 grados, por decirlo así. Es como si le faltara tener una velocidad lineal constante de los cuatro motores, que sumada a las velocidad extra (de los motores de un lado o del otro) que le aporta la maniobra de esquivar, y le permitiría hacer el giro a la vez que avanza. Tengo la programación un poco oxidada y me cuesta entender el código, disculpa mi ignorancia y gracias de nuevo por tu tiempo.
Hola, muchas gracias por todos los interesantes artículos y la cantidad de detalle que aportas, la verdad que gracias a vos, todo es mas comprendible me estoy iniciando en estos temas y tengo una duda ahi dice “Una placa Arduino Uno y una placa de expansión de IO o puede ser una placa Arduino Mega” se puede solamente con la placa arduino uno, o necesito la de la expansión si o si. Saludos.
Te contesto rápido (y luego si puedo investigo más a fondo).
Mi respuesta rápida es que para hacer un coche-robot similar al de mi ejemplo necesitas:
*controlador para los motores L298N = 6 IO (4PWM y 2 digital)
*servomotor = 1 IO (PWM)
*sensor ultrasonico = 2 IO (analógicas)
Por lo tanto necesitarías 9 IO: 5PWM, 2 digital y 2 analógicas (además de la energía positivo/negativo).
La placa Arduino Uno tiene 14 IO (6PWM) y 6 Analogicas Por lo tanto te debería alcanzar.
El pack que yo compré trae sensor de línea, bluetooth, control infrarrojos, por lo que necesita más IO, por eso la placa de expansión
Hola, buenas tardes, si funciona perfectamente con la placa arduino uno…muchas gracias por tu tiempo. Saludos.
hola, buenas noches, es posible agregar 3 sensores mas y entrenar la neurona con solo agregar una tabla que describa la funcion de los nuevos sensores?
saludos
Hola Cesar, gracias por escribir. Muy buena tu pregunta!! Si, te cuento: la idea es poder agregar muchos sensores, 3, 4 ó los que sean y que la red neuronal -luego de entrenar- defina por sí misma los mejores “pesos” de las interconexiones para generalizar el conocimiento y hacer que el coche (o el robot que sea) tome las decisiones correctas, sin ayuda externa.
Habría que ver es si al agregar nuevos sensores, necesitaremos más neuronas en la capa oculta y/o agregar una nueva capa oculta. Ahí está la prueba y error y tomar decisiones en base a la experiencia de trabajo con Redes Neuronales.
Hola, primeramente debo decir que me ha gustado la información, esta bien detallada y explicada, solamente tengo una duda, me gustaría utilizar esta red neuronal solamente con 2 motores en vez de cuatro, estoy iniciando en este tema de las redes neuronales, y me gustaría que me ayudaras diciéndome, que parte del código tengo que modificar para poder ultizar esta red solo con dos motores.
Saludos
Hola Ricardo, estoy con muy poco tiempo últimamente, disculpa la tardanza. Para 2 motores deberías modificar tus datos de entrenamiento para que sean sólo 2 salidas en vez de 4.
Deberás entrenar la red Python nuevamente pero con esas 2 salidas y cuando tengas los pesos de la nueva red, cambiar también el código en Arduino para que maneje sólo 2 outputs (en vez de 4!).
Intentaré enviarte el código por email, pero te animo a que lo modifiques tu mismo!!
Hola. a todos los que me leen.. como a. Muchos nos interesa aprender ia, y para ser honesto es muy difícil…llevo años tratando de ver como tomarlo.. buscando lenguajes como el prólogo, por ejemplo. Cada cierto tiempo retomo esta inquietud,, curiosamente al llegar a esta pagina del amigo, me llama la atención la introducción. Que me resulta familiar, esto de estar cansados de los if, y sentencias reiterativas. Por tanto me puse en campaña este año, tomé. El curso de coursera, de machine learning, que curiosamente Juan Ignacio menciona.. ahora trato de cambiar mi windows a 64 bit, para instalar tensirflow y demás ..
Mi pregunta para no aburrir a los amigos acá. Es mi interés adaptar el programa a 2 motores, ya que es el único coche que tengo ahora, pero veo que el programa tiene arreglos o array. Me da miedo saber como modificarlo.
Sigo estudiando y quedo atento a tus. Buenos comentarios, con los agradecimientos de antemano.
R
hola ricardo buen dia, pudiste hacerlo con 2 motores?
crees que me pudieras apoyar con el codigo de favor?
gracias de antemano
Tras montar el coche he metido tu programa con la red neuronal y funciona perfecto. Gracias!
Hola Pedro, Eso sí es empezar bien el año!!! jeje gracias!!
hola muy buen dia, podrían apoyarme con el codigo para el carrito pero en 2 llantas de favor?
quedo en espera de su amable ayuda
Hola Miguel Angel, en estos días intentaré hacer pruebas con 2 motores y te aviso!. Saludos
Buen articulo, pero tengo una duda con la funcion de activacion que utilizas en el codigo, utilizas una funcion llama “tanh()” la cuel eh estado buscando y no eh encontrado de que es lo que hace en el codigo de arduino; ahora yo se que la tanh es otro tipo de funcion de activacion la cual nos puede arrojar valores de salida entre -1 y 1. Quisiera que me aclares esta parte, estas utilizando la sigmoide o la tanh para realizar la activacion de tus neuronas en el arduino ?
Hola Juan, en este caso usé la función tanh que se refiere a la “Tangente Hiperbólica” y se usa para que devuelva los valores entre -1 y 1. Te dejo enlace a Funciones Hiperbólicas en Wikipedia para que veas la gráfica. Saludos
Genial, me imagino que la red también la emtemadte usando tanh como función de activación, no ?
Quisiera utilizar una red neuronal para controlar el equilibrio de una varilla (Péndulo invertido), se puede hacer con este tipo de red multicapa ? Se que esto se hace facilmente con un arduino con la librería de control PID, pero con una red neuroal conseguiria un funcionamiento como es del PID
Hola Juan… me has sorprendido con el uso que le quieres dar. Para ser sincero se escapa un poco de mi conocimiento el Péndulo Invertido del que hablas. Imagino que si puedes plantear las entradas y salidas del sensor que utilizas llevándolo al terreno de un problema de aprendizaje supervisado, podrás utilizar redes neuronales sin problema.
Intentaré investigar más sobre este tema para ver si puedo ayudarte, o si tu puedes envíame algún enlace con más datos sobre lo que tratas de hacer.
Saludos!
Ante todo felicitarlo por su Excelente artículo. Quiero consultarle acerca de los datos obtenidos de los sensores. He observado que Los datos de distancia y angulo son del tipo double, y quizas podrían tomar valores que no necesariamente son -1, 0 o 1. Es decir ¿podría tener valores de entrada a la red neuronal de TestInput[1]=0.5 y TestInput[2] = -0.3, y la red funcionaría adecuadamente para este tipo de valores?. Muchas Gracias por su respuesta
Hola Ricardo, gracias por comentar! Como bien dices, los valores que traen los sensores pueden variar en sus valores entre -1 y 1 (ó podrían ser valores mayores también). Pero cuando usamos la función constrain, convertimos esos valores a un rango de entre -100 y 100 y luego, antes de alimentar la red hacemos la división sobre cien. Con esto conseguimos transformar siempre los valores que estén “a escala” y siempre con valores del rango -1 y 1 para que la red funcione correctamente.
Saludos! Cualquier cosa me escribes!
Hola!! Para empezar muy bueno el articulo y muchas gracias por el aporte!!
Quería ver si me pueden aclarar esta duda que esta relacionada con la pregunta principal:
El serio y el censor se fosaran para que nos den valores entre -1 y 1 para introducirlos a nuestra red, pero cuando entrenamos solo tenemos respuestas definidas para valores exactos como -1,0,1 que salida tendría que arrojarme cuando tenga datos de entrada distintos a esos valores de entrenamiento como por ejemplo 0,3 y -0,9?
Hola nuevamente.Nose de qué depende qué me contesten… alguna posibilidad de probar el código para 2 motores ?… he escrito acá, envío mi inquietud por twiter sin éxito…. disculpen que sea más lento para entender…..
Hola Rodolfo, lo tengo pendiente! Aún no pude dedicarle tiempo entre familia, trabajo y otros quehaceres! En cuento pueda, hago la prueba con dos ruedas
Ok.gracias por responder.. quizás si me enseñas acomo hacerlo … no prometo mucho, ya que tengo la cabeza llena de cosas y aún no logro reordenarla… por ejemplo, según leo no usas el coche para estrenarlo, más bien el programa en Python…. como le ingresas los valores de entradas, sin usar el auto?.. como el coche va a aprender si no lo conectas con IA ?.. Mientras tanto sigo estudiando en coursera, pero me faltará algo más práctico….. (no se si me entiendes.?)
(Algo pasa que no sale lo que escribo).
Te decía Que gracias por tu atención.
Tengo muchas inquietudes y dudas, que me dan vuelta …
Yo tengo algo de tiempo, si deseas enseñarme de cómo se hace.. no prometo mucho, dado que aún no entiendo como “se cocina.”. Leo tus apuntes de regresión, tomé el curso antes de leer tus apuntes en coursera.. mucha teoría me da vueltas en el aire…que no logro aterrizar…Como es que le enseñas aún coche a ser independiente o. Que aprender a moverse, sin que lo uses?, me refiero a enseñarle … a través de python y jupiter notebook.. ( no se si se entiende la idea)
Saludos cordiales
Hola Rodolfo, te cuento: en la jupyter notebook usamos Python para entrenar una red neuronal. Esto quiere decir, que mediante el algoritmo de backpropagation obtnemos los PESOS de las neuronas interrelacionados. Una vez que tenemos esos valores, lo que hacemos es “copiar y pegarlos” en el código de Arduino (leguaje “C”). Entonces en arduino replicamos una red como la de la notebook pero “ya entrenada”.
Interesante..necesito entonces aprender a entrenar en júpiter notebook. (Buscare que es..) mientras tanto leía con mas detenimiento; “crear una red neuronal en python desde cero”. Y descubro que debo repasar o reaprender funciones tangenciales…derivadas..integrales…matrices….uuff. No sabia que el cerebro o las neuronas sabían el ciclo común de ingeniería. … ya me esta mareando el famoso coche arduino….
(Algo pasa que no sale lo que escribo).
Te decía Que gracias por tu atención.
Tengo muchas inquietudes y dudas, que me dan vuelta …
Yo tengo algo de tiempo, si deseas enseñarme de cómo se hace.. no prometo mucho, dado que aún no entiendo como “se cocina.”. Leo tus apuntes de regresión, tomé el curso antes de leer tus apuntes en coursera.. mucha teoría me da vueltas en el aire…que no logro aterrizar…Como es que le enseñas aún coche a ser independiente o. Que aprender a moverse, sin que lo uses?, me refiero a enseñarle … a través de python y jupiter notebook.. ( no se si se entiende la idea).
Saludos cordiales…
Hola,
te escribí ayer para darte las gracias porque el coche va infinitamente mejor a cuando lo compré, pero no me aparece el comentario. Igual lo tienes que validar tú, no sé.
Pues eso, que MUCHAS GRACIAS.
Hoy lo he probado con mi peque, pero todavía sigue chocándose alguna vez. Concretamente, a veces, choca contra una pared y, en lugar de esquivarla como hace en otras ocasiones, se va hacia atrás, como un toro que va a embestir y vuelve a la pared y así 3 ó 4 veces, hasta que decide girar. ¿Sabes por qué debe ser eso?
¿Y si quiero que el coche siga recto y si se encuentra un obstáculo lo bordea y sigue hacia adelante?
No sé si te está llegando esto, la verdad…
GRACIAS
Nuria
Hola Nuria, me llegó este mensaje! El de ayer no! Mañana te contesto bien, que ahora no puedo. Saludos y gracias
Hola Nuria, me alegro que con el código funcione bien el coche. Ese comportamiento que dices, también lo he visto, de que retrocede y vuelve a embestir jaja… puede tener que ver también con el sensor de distancia y el grado que tiene al detectar, puede que justo este “al limite” de la toma de una decisión u otra (por ej, giro izq. o retroceso) y el robot se quede un poco dubitativo 😉
Por otra parte, lo de ir de un punto A hasta un punto B (y rodear obstáculos en el camino) es un gran desafío que tengo pendiente. También se puede solucionar con Machine Learning, pero con otro enfoque. Ademas para ese caso es posible que necesitemos incorporar al robot un giroscopio (o algo similar) para que pueda retomar. O que tenga “mapeado” el plano del lugar previamente. Es algo complejo aunque a nosotros -los humanos- nos resulte algo tan normal
Saludos!
hola, podrias ayudarme a modificar esta red neuronal para que solo esquive objetos a la izquierda o dereche, es para un proyecto universitario, la red no tiene que avanzar ni retroceder. muchas gracias!!
Hola Juan Ignacio,
Antes que nada felicitarte y agradecerte por el blog. Estoy en la misión de hacer un auto diferencias (con dos ruedas) usando RN. Por lo que vi ibas a hacer ensayos sobre este tema… tuvieron exito? algo que puedan compartir para hacer mas fácil la tarea?
Agradeciendo de antemano tu ayuda y la de los colega, envío un afectuoso saludo.
Buenos días, primero muchas gracias por el tutorial, es bastante útil, pero tengo una pregunta ya que no soy experto aun en el tema: ¿El auto aprende con cada viaje que realiza?? osea, en el primer viaje, va a chocar con obstaculos, y mientras mas viajes realize, los ira evitando? ….o en que momento aprende?? perdon la ignorancia….espero su respuesta, muchas gracias.
Hola Roberto, en este caso no es un “aprendizaje online”, que es al que tu te refieres. Este es un aprendizaje de la red en un momento dado y se aplica esa red tal cual. Lo que le hace flexible es que puede enfrentarse a situaciones “que antes no ha visto”, es decir, un poco de improvisación para resolver de no chocar. Pero en este caso no esta “continuamente mejorando su aprendizaje”. Eso se podría hacer también, es una buena mejora!
Hola, me parece un proyecto bastante interesante. He estado modificando el codigo en Phyton para tener 3 entradas (3 sensores ultrasonicos) y ya obtuve buenos resultados. El punto es que no se como modificar el codigo en arduino para medir la distancia de esos 3 sensores, decidi quitar los comandos respectivos al servo ya que en mi caso no lo necesito. Solo necesito que el codigo en arduino funciona unicamente para los 3 sensores. Espero pueda ayudarme, de antemano gracias.
Te felicito por la refrescada que le hiciste a tu website. Tu sitio me ha servido mucho para aprender muchos de los detalles del machine learning. Excelente guia la que hiciste, te felicito. Seguid asi!! Saludos
Hola, gracias por el comentario, me alegro que sirva la guía! Saludos e intentaré seguir escribiendo!
Hola, queria consultar de que depende la cantidad de capas ocultas de la red por ejemplo estoy tratando de hacer una red la cual tiene 8 datos de entrada y de salida unos 4 entonces mi pregunta como debo preguntarme que capas usar, cada proceso de salida es diferente y trato de usar su metodología, espero su respuesta buena persona.
Hola necesito hacer el mismo prototipo pero con 6 entradas osea 6 ruedas 3 por lado quiero hacer un rover que autoguie pero solo con el sensor de ultrasonido por el momento
Buena información, y quería saber como implementarlo para dos ruedas, porque no logro entender esa parte, o alguna explicación más a condo estaría bien, voy comenzando… Gracias
hola, yo tengo un problema, cuando compilo el programa marca error pero no me indica cual es el error.. Espero me puedas ayudar
Hola queria saber si me puedes dar una mano con el ensamblaje de las piezas ya que este seria mi primer proyecto con arduino. Te mando un saludo. Franco
Hola, soy nuevo en esto del machine learning, mi duda es si lo que usted aplica es aprendizaje supervisado o no supervisado en este proyecto?
Hola Ruben, gracias por escribir, este es un problema de tipo Supervisado, pues pasamos las etiquetas con las salidas esperadas al momento de entrenar la red.
Saludos!
Pedro, probé tu proyecto y anda perfecto gracias por compartir.
Hola Jorge, muchas gracias! Saludos
Hola Pedro, arme un auto con una placa arduino mega con dos ruedas de traccion y una rueda loca al frente para realizar los giros. Configuré los pines y cargue su programa, y funciona muy bien a mi criterio. Lo unico que hace raro y que no vi que su auto en sus videos hiciera, en algun momento que detecta un obstaculo frena y hace un giro de 360º, y como queda en el mismo lugar vuelve a girar 360º y luego hace un giro hacia derecha o izquierda y avanza. Quería consultarle tambien, que me conviene empezar a estudiar con respecto a red neuronal. Ya que es un tema muy interesante y por lo que veo muy util. Desde ya muchas gracias.
Muy buenas, enhorabuena por la iniciativa y gracias por compartirlo con tod@s nosotr@s. Me parece espectacular, tanto que me he animado a comprar un coche y la placa…
He instalado todo y le he subido el programa, parece que todo está ok pero el motor del servo gira a intervalos mayores o menores pero en la misma dirección, no hace el !clokwise
/******************************************************************
MANEJAR GIRO de SERVO
******************************************************************/
if(grados_servo<=ANGULO_MIN || grados_servo>=ANGULO_MAX){
clockwise = !clockwise; // cambio de sentido
grados_servo = constrain(grados_servo, ANGULO_MIN, ANGULO_MAX);
}
if(clockwise)
grados_servo=grados_servo+incrementos;
else
grados_servo=grados_servo-incrementos;
A ver que se os ocurre para ayudarme con este problemilla. Muchas gracias.
Es porque hay un espacio. Fijate entre el igual y el signo de admiración, deben estar juntos.
Saludos
Muchas gracias por la corrección, lamentablemente no ha funcionado…la verdad es que no me explico que puede fallar… Un saludo.
existe alguna forma de progarmarlo para que siga una ruta establecida??
Hola Felipe, Tenía intención de seguir mejorando al Robot para que reconozca imágenes y pueda navegar sólo por mi casa, pero aún no tuve tiempo..
Saludos
Hola Juan Ignacio, un gusto estar en contacto contigo!!
Una pregunta sobre la red neuronal: ¿las neuronas de la capa de entrada no tienen pesos? ¿Ni Bias?.
Creo, si mal no entiendo, que hay que actualizar los pesos y bias de las neuronas de las capas oculta y de salida.
Espero hacerme entender. Por ahí conviene llamar a la capa de entrada «nodos de entrada», porque no son neuronas con pesos y Bias. ¿Puede ser?. Un saludo amigo!!
Pregunto porque ojeando el código, se puede leer:
«# asigno valores aleatorios a capa de entrada…» y también:
«# Con esto agregamos la unidad de Bias a la capa de entrada»
Mis neuronas están en cortocircuito!! ja ja. Abrazo Juan Ignacio!!
hola que tal, estoy desarrollando este proyecto porque parece genial, pero tengo una duda, y es que ya intente usarlo con bluetooth pero no me deja, desarrolle el codigo pero no pasa nada, tendra usted la version completa usando los sensores infrarojos y el bluetooth?
Hola Gracias por escribir. No tengo hecho el código con bluetooth, lo siento.
Saludos
Hola disculpa amigo pero el coche aportaría para una empresa espero tu respuesta es que tengo que hacer un proyecto que para poder culminar mi proyecto
Buenas tardes, ocupo ayuda con el proyecto, utilicé este video para hacer mi auto, ¿igual funciona?
Buenas tardes una pregunta el carrito utiliza el control del paquete de Amazon o no!!.
Buen dìa
Tengo una incógnita, Referente a la ejemplo de la red neuronal, esta me funciona con los 4 motores por separado, es decir el ejemplo esta conectado aun puente H L298, donde solo esta conectado a dos entradas y el que tengo es de cuatro entradas.
en ese orden de ideas me tocaría declarar las los 8 pines (4 de velocidad y 4 de dirección)?
// Motor Speed
#define M1SP 3
#define M2SP 11
#define M3SP 5
#define M4SP 6
// Motor Direction
#define M1D 4
#define M2D 12
#define M3D 8
#define M4D 7
y para que funcionen los sensores adicionales, se debe de agregar mas columnas a la red neuronal
estaré atento a comentarios
feliz día
buenas tengo una duda con respecto a la programación es que quiero hacer la programación como tal automática pero que con presionar una app se controle manual. ¿Cómo se podría hacer con el código para la división de acciones y operación de ambos modos? dependiendo como quiero que se controle
Hola, he probado tu programa en smart robot v4. Pero no funciona y solo se gira en su sitio. ¿Me puedes ayudar?
Hola, si puedes envíame un mensaje por el formulario de contacto y detalla el error. Ten en cuenta que este artículo fue escrito antes de 2020 y muchas cosas pueden haber cambiado desde entonces, desde las versiones python, las de Arduino ó el propio robot!.
Saludos,
Hola, buen día.
Tengo una duda. Si yo ocupará el Shield L293d que tiene para conectar 4 motores y el servo en una única placa ¿Cambia la programación? Porque al utilizar H L298 los Input, vienen en la placa.