Arduino tiene diferentes tipos de variables para representar valores.
-
Robótica
Tutoriales de modelamiento y control de robots autónomos.
Robots móviles,brazos robóticos, UAVs y más. -
Inteligencia Artificial
Tutoriales de diseño de algoritmos para resolver problemas prácticos.
Deep Learning, Machine Learning, Algoritmos genéticos y más. -
Electrónica
Tutoriales de diseño y programación para resolver problemas prácticos.
Arduino, PICs, Raspberry PI y más.
Convertir un número en un String
Si desea convertir un número para mostrarlo como texto en un LCD o dispositivo serie, la más simple solución es utilizar las bibliotecas LCD y Serial. Pero quizás esté usando un dispositivo que no tiene este soporte integrado o si desea manipular el número como una cadena en su sketch.
Para esto, se utiliza la función itoa o ltoa. Los nombres provienen de “integer to ASCII” (itoa) y “long a ASCII ”(ltoa).
Estas funciones toman tres parámetros: el valor a convertir, el búfer que contendrá la cadena de salida y la base numérica (10 para un número decimal, 16 para hexadecimal y 2 para binario).
El siguiente sketch ilustra cómo convertir valores numéricos usando ltoa:
Para esto, se utiliza la función itoa o ltoa. Los nombres provienen de “integer to ASCII” (itoa) y “long a ASCII ”(ltoa).
Estas funciones toman tres parámetros: el valor a convertir, el búfer que contendrá la cadena de salida y la base numérica (10 para un número decimal, 16 para hexadecimal y 2 para binario).
El siguiente sketch ilustra cómo convertir valores numéricos usando ltoa:
long value = 123456; void setup() { Serial.begin(9600); } char buffer[12]; // tipo de dato long tiene 11 caracteres //(incluyendo el signo menos) y la terminación null) void loop() { ltoa(value, buffer, 10); Serial.print(value); Serial.print(" tiene "); Serial.print(strlen(buffer)); Serial.println(" digitos"); delay(1000); }
Convertir un String en un número
Necesitas convertir un String a un número que hayas recibido a través de un enlace de comunicación y necesita usarlo como un valor de punto flotante o entero.
Las funciones atoi (ASCII a int), atol (ASCII a long) y atof (ASCII a float) convierten un String en enteros, enteros long y floats respectivamente.
El siguiente sketch ilustra cómo convertir un String a valores numéricos int, long y float:
char dataInt[5] = "1234"; char dataLongInt[11]="2147483647"; char dataFloat[5]="1.23"; int cInt=0; long cLongInt=0; float cFloat=0.0; void setup() { Serial.begin(9600); } void loop() { cInt=atoi(dataInt); cLongInt=atol(dataLongInt); cFloat=atof(dataFloat); Serial.print("Original data : "); Serial.print(cInt); Serial.print(","); Serial.print(cLongInt); Serial.print(","); Serial.println(cFloat); // Operaciones con datos cInt=cInt+1; cLongInt=cLongInt-1; cFloat=cFloat+0.07; Serial.print("Modificated data : "); Serial.print(cInt); Serial.print(","); Serial.print(cLongInt); Serial.print(","); Serial.println(cFloat); delay(1000); }
Machine learning para predecir el precio de una vivienda.
1:21 p.m.ai, boston housing, inteligencia artificial, keras, machine learning, regresion, regresion lineal, tensorflow
No hay comentarios.
Introducción
Este tutorial implementa un modelo de red neuronal para predecir el precio de una vivienda utilizando el conjunto de datos Boston_Housing. El objetivo es predecir un valor continuo, por lo tanto, estamos frente a un problema de regresión. El código esta disponible en la sección descargas opción Inteligencia Artificial
Cargar conjunto de datos Boston Housing
El conjunto de datos contiene 506 ejemplos, divididos entre 404 muestras de entrenamiento y 102 muestras de prueba.
El conjunto de datos contiene 13 características diferentes:
- Tasa de criminalidad per cápita.
- La proporción de terrenos residenciales divididos en zonas para lotes de más de 25,000 pies cuadrados.
- La proporción de acres de negocios no minoristas por ciudad.
- Variable dummy de Charles River (= 1 si el tramo limita el río, 0 de lo contrario).
- Concentración de óxidos nítricos (partes por 10 millones).
- El número promedio de habitaciones por vivienda.
- La proporción de unidades ocupadas por sus propietarios construidas antes de 1940.
- Distancias ponderadas a cinco centros de empleo de Boston.
- Índice de accesibilidad a carreteras radiales.
- Tasa de impuesto a la propiedad de valor completo por $ 10,000.
- Proporción de alumno por profesor por ciudad.
- 1000 * (Bk - 0.63) ** 2 donde Bk es la proporción de personas negras por ciudad.
- Porcentaje de menor estatus de la población.
Y cada característica de los datos de entrada tiene una escala diferente. Por ejemplo, algunos valores son proporciones, que toman valores entre 0 y 1; otros toman valores entre 1 y 12, otros entre 0 y 100, y así sucesivamente.
Los objetivos, etiquetas o labels son los precios de la vivienda en miles de dólares registrados en la década de 1970. Los precios son típicamente entre $ 10,000 y $ 50,000.
Los objetivos, etiquetas o labels son los precios de la vivienda en miles de dólares registrados en la década de 1970. Los precios son típicamente entre $ 10,000 y $ 50,000.
Normalizar las características
Se recomienda normalizar los datos que usan escalas e intervalos diferentes. Para cada característica, reste la media de la característica y divida por su desviación estándar. La red podría adaptarse automáticamente a datos tan heterogéneos, pero dificultaría el aprendizaje.
Construir el modelo
En este turorial se implementa un modelo secuencial con dos capas ocultas totalmente conectadas de 64 nodos (neuronas) y la función de activación relu, y una capa de salida que devuelve un único valor continuo.
Debido a que no hay mucha información de entrenamiento, se usa una red pequeña con pocas capas ocultas y nodos para evitar el sobreajuste.
Definir la función de pérdida, optimizador y métrica
Para el problema de regresión es común utilizar la función de pérdida error cuadrático medio (mse), el optimizador utilizado es el rmsprop y una métrica de regresión común es el error absoluto medio (mae).
Entrenar el modelo
El modelo se entrena durante 300 épocas, los datos de entrenamiento se dividen en un 20% para validación y además se registra el entrenamiento y la precisión de validación en el objeto history.
Métodos numéricos aplicados a la ingeniería
Introducción
Este tutorial presenta los métodos numéricos más utilizados en el área de ingeniería. Por ejemplo, en el controlador PID se puede aproximar la acción integral y derivativa utilizando estos métodos. Además, estas técnicas se utilizarán en los siguientes blogs para el modelamiento y control de Robots Autónomos.
Las pruebas se realizaron en Matlab, más detalles en el siguiente video.
En robótica se requiere medir la razón de cambio de las variables del robot. Por ejemplo la razón de cambio de la posición es la velocidad y la razón de cambio de la velocidad es la aceleración.
La derivada xp puede ser descrita por la pendiente de la recta formada entre las muestras (k-1)T y kT de la función, conocida como diferenciación con un paso atrás (backward difference), tal como muestra la figura 1.
Donde k={0, 1, 2, .....} y T es un intervalo de tiempo constante (tiempo de muestreo).
También se puede aproximar la derivada entre las muestras kT y (k+1)T de la función, conocida como diferenciación hacia adelante (forward difference).
Implementación en Matlab
La figura 2 y 3 muestra la diferenciación numérica real, aproximada de una función senoidal.
Considerando que la integral de la aceleración es la velocidad, y la integral de la velocidad es la posición. Es decir, existe una relación entre la integral y la derivada. Por lo tanto se puede considerar que son operaciones inversas.
Entonces si se considera la diferenciación hacia adelante (forward difference) la integral numérica esta dada por.
Implementación en Matlab
La figura 4 y 5 muestra la integración numérica real, aproximada de una función coseno. La diferenciación numérica permite aproximar la derivada de una función. En la figura 5 se ha disminuido el tiempo de muestreo T a 0.01 segundos resultando una mejor aproximación.
Las pruebas se realizaron en Matlab, más detalles en el siguiente video.
Diferenciación numérica
La diferenciación numérica permite aproximar la derivada de una función. La derivada de una función representa la razón de cambio con respecto al tiempo.En robótica se requiere medir la razón de cambio de las variables del robot. Por ejemplo la razón de cambio de la posición es la velocidad y la razón de cambio de la velocidad es la aceleración.
La derivada xp puede ser descrita por la pendiente de la recta formada entre las muestras (k-1)T y kT de la función, conocida como diferenciación con un paso atrás (backward difference), tal como muestra la figura 1.
Donde k={0, 1, 2, .....} y T es un intervalo de tiempo constante (tiempo de muestreo).
Figura 1. Aproximación de la derivada de una función.
También se puede aproximar la derivada entre las muestras kT y (k+1)T de la función, conocida como diferenciación hacia adelante (forward difference).
Implementación en Matlab
La figura 2 y 3 muestra la diferenciación numérica real, aproximada de una función senoidal.
Figura 2. Diferenciación con un paso atrás (backward difference) con T=0.1s.
Figura 3. Diferenciación hacia adelante (forward difference) con T=0.1s.
Integración numérica
Considerando que la integral de la aceleración es la velocidad, y la integral de la velocidad es la posición. Es decir, existe una relación entre la integral y la derivada. Por lo tanto se puede considerar que son operaciones inversas.
Entonces si se considera la diferenciación hacia adelante (forward difference) la integral numérica esta dada por.
Implementación en Matlab
La figura 4 y 5 muestra la integración numérica real, aproximada de una función coseno. La diferenciación numérica permite aproximar la derivada de una función. En la figura 5 se ha disminuido el tiempo de muestreo T a 0.01 segundos resultando una mejor aproximación.
Figura 4. Integración numérica considerando (forward difference) con T=0.1s.
Figura 5. Integración numérica considerando (forward difference) con T=0.01s.
Sintonía de controlares PID basada en reglas.
2:08 p.m.Arduino, Arduino Due, Control, electronica, Filtro, PID, Transformada z
No hay comentarios.
Introducción
En este tutorial se muestra cómo sintonizar un controlador PID digital en arduino basado en reglas.
Para mas información sobre el algoritmo de control y el código ingresa a mi anterior blog.
PID digital de luminosidad con arduino
La función de transferencia para el controlador PID ISA digital esta dada por
Un tiempo de muestreo optimo debe ser menor que el tiempo de establecimiento (te) o tiempo de retardo (tr) del sistema en lazo abierto. En el modelo Ziegler-Nichols se considera T<te/10 o T<tr/4.
Para mas información sobre el algoritmo de control y el código ingresa a mi anterior blog.
PID digital de luminosidad con arduino
La función de transferencia para el controlador PID ISA digital esta dada por
Tiempo de muestreo (T)
El control digital o discreto trabaja en instantes de tiempo predeterminados llamado tiempo de muestreo T. Fundamentalmente T es el tiempo de ejecución del algoritmo de control, normalmente el tiempo de ejecución suele ser mayor que el periodo de muestreo de los conversores A/D. En algunos casos, el periodo de muestreo se diseña para que sea mayor que el tiempo de tiempo de ejecución, cuando las constantes de tiempo del proceso son muy grandes (Planta de temperatura). Sin embargo, un periodo de muestreo alto conlleva una pérdida de la estabilidad relativa del sistema.Un tiempo de muestreo optimo debe ser menor que el tiempo de establecimiento (te) o tiempo de retardo (tr) del sistema en lazo abierto. En el modelo Ziegler-Nichols se considera T<te/10 o T<tr/4.
Acción proporcional (P)
La acción proporcional tiene
una implementación directa, multiplica cada muestra de la señal de
error actual por un valor de ganancia Kp. Es decir, genera una
señal de control que es proporcional a la señal de error.
Figura 1. Respuesta del control P con Kp=0.055.
Figura 2. Respuesta del control P con Kp=0.1.
Figura 3. Respuesta del control P con Kp=0.5.
En base a los resultados el aumento de la ganancia Kp permite reducir el error en estado estacionario. Sin embargo, no permite eliminar el error. Ademas, aumentando la ganancia proporcional disminuye la estabilidad
Acción integral (I)
La función principal de la acción integral es asegurarse de que la salida del proceso Pv coincida con el punto de ajuste deseado Sp en estado estacionario.
Figura 4. Respuesta del control PI con Kp=0.055 y Ti=0.1.
Figura 5. Respuesta del control PI con Kp=0.055 y Ti=0.01.
Figura 6. Respuesta del control PI con Kp=0.055 y Ti=0.001.
Figura 7. Respuesta del control PI con Kp=0.055 y Ti=0.0001.
En base a los resultados el error decae más rápidamente
si se disminuye el tiempo de integración. Sin embargo, disminuyendo demasiado el tiempo de
integración disminuye la estabilidad.
Acción de control derivativa (D)
Un controlador con acción derivativa se puede interpretar como si el control se hiciese proporcional a la salida predicha del proceso.
Figura 8. Respuesta del control PID con Kp=0.064, Ti=0.01 y Td=0.
Figura 9. Respuesta del control PID con Kp=0.064, Ti=0.01 y Td=0.0095.
Figura 10. Respuesta del control PID con Kp=0.064, Ti=0.01 y Td=0.01.
Figura 11. Respuesta del control PID con Kp=0.064, Ti=0.01 y Td=0.08.
En base a los resultados el aumento del tiempo derivativo mejora la estabilidad pero empeora otra vez cuando el tiempo derivativo se hace demasiado grande.
Un control PID correctamente sintonizado es rápido, estable y tiene un error en estado estable que tiende a
cero. El objetivo se consigue con Kp=0.03, Ti=0.01 y Td=0.01.
Figura 12. Respuesta del control PID con Kp=0.03, Ti=0.01 y Td=0.01.
Conclusión
Aumentando la ganancia proporcional disminuye la estabilidad.
El error decae más rápidamente si se disminuye el tiempo de integración. Sin embargo, disminuyendo demasiado el tiempo de integración disminuye la estabilidad.
Aumentando el tiempo derivativo mejora la estabilidad pero empeora otra vez cuando el tiempo derivativo se hace demasiado grande.
El error decae más rápidamente si se disminuye el tiempo de integración. Sin embargo, disminuyendo demasiado el tiempo de integración disminuye la estabilidad.
Aumentando el tiempo derivativo mejora la estabilidad pero empeora otra vez cuando el tiempo derivativo se hace demasiado grande.
PID digital de luminosidad con arduino
Introducción
Este tutorial muestra cómo implementar un controlador PID digital de luminosidad con arduino. Cabe señalar que más de la mitad de los controladores industriales que se usan hoy en día utilizan
esquemas de control PID o PID modificado.
En la siguiente figura se muestra el diagrama de bloques del sistema en lazo cerrado.
Figura 1. Diagrama de bloques del sistema en lazo cerrado.
Donde Sp es el punto de ajuste
deseado, Pv es la variable de proceso medida, e es el error (Sp-Pv) y Cv es variable de
control.
El control PID implementado es de la forma estándar algunas veces llamado algoritmo ISA, o ideal.
Figura 2. Diagrama de bloques del control PID ISA .
La función de transferencia en el dominio Z para el controlador PID ISA digital esta dada por
La señal de control Cv es la suma de
tres términos: P (que es proporcional al error), I (que es
proporcional a la integral del error), y el término D (que es proporcional a la
derivada del error). Los parámetros del controlador son la ganancia
proporcional Kp, el tiempo integral Ti, el tiempo derivativo Td y el tiempo de muestreo T.
Para implementar el algoritmo de control en el arduino es necesario pasar la ecuación anterior a ecuaciones en diferencias, para esto se utiliza las siguientes propiedades de la transformada Z.
Aplicando las propiedades de la transformada Z se obtiene
Donde e(k) representa el error en el instante actual y e(k-1) el error en el instante anterior.
Hardware requerido
- 1 Arduino
- 1 Led blanco de 5mm
- 2 Resistencias de 10k ohm
- 1 Potenciómetro de 10k ohm
- 1 Protoboard
- Cable
Circuito
En la figura 3 se muestra el esquema de conexión. Para la fuente de luminosidad se utiliza un led ultrabrillante de 5 mm,
color blanco en serie con una resistencia de 10k ohm. El pin 6 se utiliza como salida de control (Cv) y para la lectura de la variable de proceso (Pv) se usa una LDR mediante un divisor de voltaje.
Para variar el punto de ajuste (Sp) se utiliza un potenciómetro de 10k ohm. Para un mayor rango de control colocar el circuito en una caja cerrada como la figura 4.
Para variar el punto de ajuste (Sp) se utiliza un potenciómetro de 10k ohm. Para un mayor rango de control colocar el circuito en una caja cerrada como la figura 4.
Figura 3. Esquema de conexión.
Código
Primero definimos nuestro rango de control aplicando el mínimo Cv (0 ciclo de trabajo PWM al 0%) y máximo Cv (255 ciclo de trabajo 100%) y leyendo el valor digital del sensor (0-1023) mediante el siguiente programa.
Rango_de_Control.ino
Rango_de_Control.ino
float sensorValue = 0; int PWM=0; char cadena[30]; byte posicion = 0; void setup() { Serial.begin(9600); } void loop() { if (Serial.available()) { memset(cadena, 0, sizeof(cadena)); while (Serial.available() > 0) { cadena[posicion] = Serial.read(); posicion++; delay(10); } posicion = 0; PWM = atoi(cadena); } sensorValue=analogRead(A0); analogWrite(6,PWM); Serial.print("sensorValue : "); Serial.print(sensorValue); Serial.print(" PWM : "); Serial.println(PWM); delay(1000); }
Ingresar el Cv mediante el monitor serial de Arduino.
Figura 4. Rango de control mínimo (0 PWM ~ 40 valor digital).
Figura 5. Rango de control máximo (255 PWM ~ 755 valor digital).
A continuación se implementa el algoritmo PID. Para mas detalles del código mira el vídeo.
Control_PID.ino
float Pv = 0; // variable de proceso medida (porcentaje luminosidad) float Sp= 0; // punto de ajuste deseado (porcentaje luminosidad) int Cv=0; // variable manipulada (MV) o variable de control (PWM) float error=0; //error actual float error_1=0; // error anterior float Kp=0.05; // ganancia proporcional float P=0.0; // término P float Ti=0.03; // tiempo integral float I=0.0; // término I float Td=0.0001; // tiempo derivativo float D=0.0; // término D int T=100; // tiempo de muestreo milisegundos // Variables para asegurar tiempo muestreo unsigned long pasado=0; unsigned long actual; void setup() { Serial.begin(9600); } void loop() { actual=millis(); // milisegundos desde que se inició el programa unsigned long dt=actual-pasado; if(dt>=T) { pasado=actual; Pv=promedio(100,0); // Escalamiento de Pv Pv=abs(map(Pv,5,880,0,100)); Sp=promedio(100,1); // Escalamiento de Pv Sp=map(Sp,0,1023,0,100);// Escalamiento de Sp error = Sp - Pv; // Cálculo de error P=Kp*error; // término P I=I+(Kp/Ti)*error*(T/1000.0); // término I D=D=(Kp*Td)*((error-error_1)/(T/1000.0)); // término D error_1=error; // error anterior Cv=P+I+D; // Control PID Cv=constrain(Cv,0,255);// Restricción de acción de control analogWrite(6,Cv); Serial.print("Sp : "); Serial.print(Sp); Serial.print(" Pv : "); Serial.print(Pv); Serial.print(" Cv : "); Serial.println(Cv); } } float promedio(int numeroLecturas,int sensorPin) { float aux=0.0; for (int conta = 1; conta <=numeroLecturas ; conta++) { aux=aux+analogRead(sensorPin); // Escalamiento de Pv delayMicroseconds(10); } return (aux/numeroLecturas); }
Resultados