Saltar al contenido

Comunicación Serial Arduino Simulink/Matlab

Controleras y controleros, en esta entrada aprenderemos como configurar el SIMULINK [Matlab] para que pueda recibir datos o transmitir datos usando una comunicación serial con nuestra placa de desarrollo del Arduino, sin embargo, el procedimiento puede ser aplicado con otro microcontrolador (PIC, ESP, Raspberry Pi Pico, etc), con un PLC, un sensor o cualquier otro instrumento que posea comunicación serial.

Antes de comenzar, te hago la invitación para que veas nuestro CURSO GRATUITO DE ARDUINO.

Y que te suscríbas al canal si te gusta la programación, los microcontroladores, el modelado de sistemas y la teoría del control.

Instrument Control Toolbox Simulink

Para poder realizar la comunicación serial entre Arduino (o cualquier otro instrumento) y Simulink, será necesario tener instalado el instrument control toolbox

Con Instrument Control Toolbox, es posible generar bien sea en MATLAB o SIMULINK para transmitirlos a un instrumento.

De la misma forma, tambien se pueden leer datos en MATLAB o SIMULINK para su análisis y visualización. 

Si no tienes instalado el toolbox, dentro de MATLAB puedes ir a la pestaña HOME y dar Click en Add Ons/Get Add-Ons y buscar por: instrument control toolbox.

Agregar el instrument control toolbox

Una vez instalada la biblioteca, procedemos a abrir el SIMULINK, y verificamos que efectivamente el BLOCKSET del ToolBox se encuentre instalado y que tenga todos los bloques de comunicación como Comunicación Serial, TCP/IP, UDP, I2C, SPI, y Bluetooth.

Instrument control toolbox Simulink
Comunicación Serial con PIC

Comunicación Serial con PIC

Control en Cascada

Control en Cascada

Comunicación Serial Arduino Simulink/Matlab

Una vez instalado el toolbox procedemos a efectuar la Comunicación Serial entre Arduino y Simulink/Matlab.

Inicialmente es muy importante que CONECTES tu ARDUINO o INSTRUMENTO al Computador ANTES de Abrir el MATLAB, para que el software consiga detectar adecuadamente el dispositivo.

Antes de comenzar a transmitir o recibir datos, es importante entender que Matlab por defecto trabaja con Números punto flotante precisión doble que ocupan 8 bytes. Sin embargo, el punto flotante de doble precisión de arduino ocupa 4 bytes, lo que es equivalente a un single en Matlab. Por lo tanto deberemos hacer alguna conversión de datos dentro del Simulink con el bloque Data Type Conversion.

Ahora, si deseas aprender SIMULINK DESDE CERO, te invito a que te matricules a mi Curso el cual se encuentra disponible en UDEMY. Basta con darle click al siguiente botón y te volveras un experto manipulando este software:

Con el objetivo de lograr la Comunicación Serial entre Arduino y Simulink vamos a construir el siguiente diagrama (todos los archivos están disponibles para descarga al final del post):

Comunicación Serial Arduino Simulink/Matlab
Comunicación Serial Arduino Simulink/Matlab

Transmisión de Datos Serial

Los tres primeros bloques de la transmisión de datos son:

  • Pulse Generator: Genera un tren de pulsos de periodo 4 segundos con un ancho del 50%
  • Zero-Order Hold: Discretiza la señal con un periodo de muestreo de 0.05s
  • Data Type Conversion: convierte el double de Matlab (8 bytes) para un single (4 bytes) para que pueda ser interpretado por arduino.
  • Serial Send: Configuramos el puerto de comunicación serial [COM] en el cual está conectado nuestro Arduino o instrumento.

Recepción de Datos Serial

En esta etapa también tenemos un Data Type Conversion para transformar el double proveniente de Arduino (4 bytes) para el double de Matlab de (8 bytes)

Tenemos también el bloque Serial Receive en el cual configuraremos la recepción serial.

En este caso, configuramos el puerto de comunicación COM, colocamos el tipo de dato SINGLE, y habilitamos el Data Frame:

En el header colocamos el caracter de inicio con el que indicamos el inicio de la trama de datos. En mi caso, yo coloqué un ‘V’ como caractér de inicio el cual voy a programar en el Arduino. Ustedes pueden colocar cualquier otro caractér o palabra.

En el terminator colocamos el caracter de finalización de la trama de datos. En mi caso coloque el ‘\n’.

Finalmente también colocamos el periodo de muestreo de 0.05s.

Configuración Serial

Con el bloque Serial Configuration, realizamos la configuración serial del dispositivo, por ejemplo la velocidad en Baudios, los bits de paridad, los bits de datos, el bit de parada, el puerto de comunicación, etc.

Programa de Comunicación Serial Arduino Simulink/Matlab

Procedemos a configurar el programa en Arduino (en mi caso estoy empleando un Leonardo, pero puedes emplear cualquier otra placa), el cual va a transmitir y recibir datos por el puerto serial con Simulink.

Para este caso implementaremos el siguiente circuito:

Lista de Materiales

  • Placa de Desarrollo de Arduino
  • Motor DC con Encoder de 5v o 12v
  • Driver de Potencia Puente H (L298)
  • Potenciometro 5k (o cualquiera)
  • Cables
  • Fuente de Alimentción de 5v o 12v dependiendo del motor empleado.

Nota (Comunicación Serial en Arduino)

En el video de YouTube, pueden notar que en el void setup() NO configuré el Serial.begin().

No es estrictamente necesario usar Serial.begin() en el void setup() para la comunicación USB CDC en Arduino. La razón es que, en algunas placas de Arduino, como el Leonardo, Micro y Due, la comunicación USB CDC se maneja a través de un chip separado, y no es necesario inicializarla explícitamente con Serial.begin().

Sin embargo, en placas como Arduino Uno, Nano y Mega, que utilizan el ATmega328P o ATmega2560 y no tienen un chip separado para la comunicación USB, es necesario usar Serial.begin() para configurar el UART (Universal Asynchronous Receiver-Transmitter) e iniciar la comunicación serial.

Aunque no sea necesario en algunos casos, es una buena práctica incluir Serial.begin() en tu código, ya que hace que tu programa sea más compatible con diferentes placas Arduino y permite ajustar la velocidad de transmisión de datos (baud rate) si es necesario.

Funcionamiento

La idea del código es activar y desactivar un Motor DC con Enconder en el Arduino con el cual podremos leer la velocidad del motor en Radianes/s.

La activación y desactivación del motor vendrá dada por el simulink empleando la comunicación serial, para eso fue colocado el generador de pulsos cuadrados.

El Arduino enviará los datos de velocidad hacia el simulink, los cuales son graficados usando un Scope.

Suscríbete a este sitio WEB para estar enterado de las nuevas entradas!

Código

Todos los códigos del Arduino y el Simulink los puedes descargar en el siguiente botón:

A continuación muestro cual sería el código empleado en el Arduino:

//***************************************************//
//***************************************************//
//*****   Recepción y transmición de datos      *****//
//*****   de velocidad de un encoder de un      *****//
//*****   motor DC hacia Simulink para          *****//
//*****   Validación de modelo matematico       *****//
//*****                                         *****//
//***** by: Sergio Andres Castaño Giraldo       *****//
//***** https://controlautomaticoeducacion.com/ *****//
//*****                                         *****//
//***************************************************//
//***************************************************//

// this library includes the ATOMIC_BLOCK macro.
#include <util/atomic.h>

#define ENCODER_A       2 // Amarillo
#define ENCODER_B       3 // Verde

// Pines de Control Shield
const int E1Pin = 10;
const int M1Pin = 12;

//Estructura del Motor
typedef struct{
  byte enPin;
  byte directionPin;
}Motor;

//Estructura Union
typedef union{
  float number;
  uint8_t bytes[4];
}valor;

//Variable Union
valor velocidad;

//Creo el motor
const Motor motor = {E1Pin, M1Pin};

//Constantes de dirección del Motor
const int Forward = LOW;
const int Backward = HIGH;

//Variable global de pulsos compartida con la interrupción
volatile int pulsos = 0;
unsigned long timeold;
float resolution = 374.22;
//Variable Global Velocidad
int vel = 0;
float value;
float rpm=0;

void setup(){
  Serial.begin(9600);
  // set timer 1 divisor to  1024 for PWM frequency of 30.64 Hz
  TCCR1B = TCCR1B & B11111000 | B00000101;
  //Configura Motor
  pinMode(motor.enPin, OUTPUT);
  pinMode(motor.directionPin, OUTPUT);
  //Configurar Interrupción
  timeold = 0;
  attachInterrupt(digitalPinToInterrupt(ENCODER_A),leerEncoder,RISING);

}

void loop(){
  //Pregunta si tenemos un dato a recibir
  if(Serial.available() > 0){
      value = recepcion();
  }
  
  //Transforma el valor del voltaje (0-5) a velocidad
  vel = map(value,0,5,0,255);

  //Activa el motor dirección Backward con la velocidad
  setMotor(motor, vel, true);

  //Espera un segundo para el calculo de las RPM
  if (millis() - timeold >= 50)
  {
      //Modifica las variables de la interrupción forma atómica
      ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
        rpm = float((60.0 * 1000.0 / resolution ) / (millis() - timeold) * pulsos);
        timeold = millis();
        pulsos = 0;
         velocidad.number = rpm * 0.10472; //rad/s
         Serial.write('V');
         for(int i=0; i<4; i++){
              Serial.write(velocidad.bytes[i]);
         }
         Serial.write('\n');
      }
   }
}

//Función para dirección y velocidad del Motor
void setMotor(const Motor motor, int vel, bool dir){
  analogWrite(motor.enPin, vel);
  if(dir)
    digitalWrite(motor.directionPin, Forward);
  else
    digitalWrite(motor.directionPin, Backward);
}

//Recibir Flotante
float recepcion(){
  int i;
  valor buf;
  for(i=0; i<4; i++)
    buf.bytes[i] = Serial.read();  

  return buf.number;
}

//Función para la lectura del encoder
void leerEncoder(){
    pulsos++; //Incrementa una revolución
}

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.