• 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.

Tipos de variables

Arduino tiene diferentes tipos de variables para representar valores.
Puede usar la Tabla para determinar el tipo de variable que se ajusta al rango de valores de su aplicación.


Compartir:

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:
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);

}

Compartir:

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 intlong 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);

}

Compartir:

Machine learning para predecir el precio de una vivienda.

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.


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.

Figura 1. Error absoluto medio durante 300 épocas.


El gráfico muestra que el error promedio es de aproximadamente $ 2,500 dólares.
Entrenar el modelo
Finalmente, se predice algunos precios de vivienda usando el conjunto de prueba.



Figura 2. Resultado al problema de regresión.




Compartir:

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.


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ó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.



Compartir:

Sintonía de controlares PID basada en reglas.

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


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 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.
Compartir:

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 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 (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.



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

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

La siguiente figura muestra la respuesta del controlador a varios escalones.


Figura 6.  Respuesta del sistema en lazo cerrado.
Compartir:

Donaciones

Suscribete

SÍGUENOS EN FACEBOOK

Posts Populares

Categorías

Post Recientes