Unidad 2. Protocolos ascii

Introducción

En la unidad anterior te has concentrado en la construcción de software para sistemas embebidos. En esta unidad aprenderás como integrar a una plataforma de cómputo interactiva dichos sistemas embebidos mediante el uso de HILOS y protocolos de comunicación ASCII.

Propósitos de aprendizaje

Construir aplicaciones interactivas utilizando múltiples hilos para la producción y el prototipado de experiencias interactivas.

Integrar controladores con aplicaciones interactivas mediante el uso de protocolos seriales ascii.

Temas

  • Repaso de tipos de dato valor y tipos referencia en C#.
  • Concepto de hilo y programación básica.
  • Conceptos básicos de sincronización de hilos.
  • Introducción al concepto de máquina virtual y su uso en la plataforma interactiva Unity.
  • Construcción de aplicaciones tipo consola que hagan uso del puerto serial.
  • Protocolos de comunicación ASCII.

Trayecto de acciones

Ejercicio 1

Realiza esta guía.

Ejercicio 2

Lee este blog hasta la la sección que dice Join and Sleep y reproduce los ejemplos que están allí. Analiza con detenimiento cada ejemplo.

Ejercicio 3

Hasta este punto del curso hemos utilizado .NET para la construcción de aplicaciones interactivas. En este ejercicio te propongo que indagues un poco más sobre la plataforma de software que estamos usando:

Ejercicio 4

Al finalizar el curso estaremos utilizando el motor Unity para construir aplicaciones interactivas a las que se integren sensores y actuadores.

Profundiza un poco más sobre la relación entre .NET, código compilado y Unity:

Ejercicio 5

La idea del ejercicio es comunicar a través del puerto serial el computador con un controlador, en este caso un ESP32. Recuerda que la aplicación del computador será tipo consola .NET framework.

Estudia con detenimiento el código para el controlador y para el computador.

  • ¿Quién debe comenzar primero, el compu o el controlador? ¿Por qué?

Programa el arduino con este código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void setup() {
  Serial.begin(115200);
}

void loop() {
  if(Serial.available()){
    if(Serial.read() == '1'){
      Serial.print("Hello from ESP32");
    }
  }
}

Y este es el código para el computador:

 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
using System;
using System.IO.Ports;

namespace hello_serialport{
    class Program{
        static void Main(string[] args)
        {
          SerialPort _serialPort = new SerialPort();
          // Allow the user to set the appropriate properties.
          _serialPort.PortName = "/dev/ttyUSB0";
          _serialPort.BaudRate = 115200;
          _serialPort.DtrEnable = true;
          _serialPort.Open();
          byte[] data = {0x31};
          _serialPort.Write(data,0,1);
          byte[] buffer = new byte[20];

          while(true){
              if(_serialPort.BytesToRead > 0){
                  _serialPort.Read(buffer,0,20);
                  Console.WriteLine(System.Text.Encoding.ASCII.GetString(buffer));
                  Console.ReadKey();
                  _serialPort.Write(data,0,1);
              }
          }
        }
    }
}

Ejercicio 6

Ahora programa tanto el controlador como el PC con los siguientes códigos.

NO OLVIDES! analiza el código con detenimiento, entiéndelo.

Este es el código para programar en el arduino:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  void setup() {
    Serial.begin(115200);
  }

  void loop() {

    if(Serial.available()){
      if(Serial.read() == '1'){
        delay(1000);
        Serial.print("Hello from ESP32\n");
      }
    }
  }

Este es el código para programar el computador

 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
  using System;
  using System.IO.Ports;
  using System.Threading;

  namespace serialTestBlock
  {
  class Program{
          static void Main(string[] args)
          {
              SerialPort _serialPort = new SerialPort();
              _serialPort.PortName = "/dev/ttyUSB0";
              _serialPort.BaudRate = 115200;
              _serialPort.DtrEnable = true;
              _serialPort.Open();

              byte[] data = {0x31};
              byte[] buffer = new byte[20];
              int counter = 0;

              while(true){
                  if(Console.KeyAvailable == true){
                      Console.ReadKey(true);
                      _serialPort.Write(data,0,1);
                      string message = _serialPort.ReadLine();
                      Console.WriteLine(message);
                  }
                  Console.WriteLine(counter);
                  counter = (counter + 1) % 100;
                  Thread.Sleep(100);
              }
          }
      }
  }
  • Conecta el controlador.
  • Modifica el código del computador asignando el puerto serial correcto.
  • Corra el código del computador.
  • Al presionar cualquier tecla qué pasa?

Ejercicio 7

Te diste cuenta que al presionar una tecla, el conteo se detiene un momento?

Al construir aplicaciones interactivas no te puedes dar este lujo. Piensa en esto: ¿Y si en vez de imprimir un contador estás renderizando una escena? Por tanto, las comunicaciones con el controlador y el proceso de impresión del contador en la pantalla deben ser dos flujos independientes, es decir, dos hilos.

¿Quieres intentarlo tu mismo?

Advertencia

Alerta de spoiler

El siguiente código muestra una posible solución al reto

 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
  using System;
  using System.IO.Ports;
  using System.Threading;

  namespace SerialTest
  {
      class Program
      {
          static void Main(string[] args)
          {

              int counter = 0;

              Thread t = new Thread(readKeyboard);
              t.Start();

              while (true)
              {
                  Console.WriteLine(counter);
                  counter = (counter + 1) % 100;
                  Thread.Sleep(100);
              }
          }

          static void readKeyboard()
          {

              SerialPort _serialPort = new SerialPort(); ;
              _serialPort.PortName = "COM4";
              _serialPort.BaudRate = 115200;
              _serialPort.DtrEnable = true;
              _serialPort.Open();

              byte[] data = { 0x31 };

              while (true) {
                  if (Console.KeyAvailable == true)
                  {
                      Console.ReadKey(true);
                      _serialPort.Write(data, 0, 1);
                      string message = _serialPort.ReadLine();
                      Console.WriteLine(message);
                  }
              }
          }
      }
  }

PROYECTO

Debes realizar un sistema interactivo compuesto por una aplicación en el PC y un controlador al cual se conectan varios sensores y actuadores.

Para el controlador tienes:

  • Dos sensores digitales
  • Dos sensores analógicos: valores de 0 a 1023
  • Dos actuadores digitales.
  • Dos actuadores analógicos (pwm)

El controlador se conecta a un computador a través del puerto USB y se comunica utilizando la interfaz Serial.

Realiza un programa, para le controlador, que haga las siguientes tareas concurrentes:

  • Recibir comandos a través de la interfaz Serial
  • Enciende y apaga un LED a una frecuencia de 10 Hz
  • Enciende y apaga un LED a una frecuencia de 5 Hz.

Los comandos recibidos por el puerto serial serán los siguientes:

  • read D1. Este comando hace que se envíe al PC el valor del sensor digital 1. El controlador devuelve la cadena: D1 estado. Donde estado puede ser 1 o 0.
  • read D2: enviar al PC el valor del sensor digital 2. El controlador devuelve la cadena: D2 estado. Donde estado puede ser 1 o 0.
  • read A1: enviar el PC el valor del sensor analógico 1. El controlador devuelve la cadena A1 valor. Donde valor está entre 0 y 1023.
  • read A2: enviar el PC el valor del sensor analógico 2. El controlador devuelve la cadena A2 valor. Donde valor está entre 0 y 1023.
  • write O1 estado: donde estado puede ser 1 o 0. Activa o desactiva la salida digital 1
  • write O2 estado: donde estado puede ser 1 o 0. Activa o desactiva la salida digital 2
  • write P1 valor: donde valor puede ser de 0 a 255. Escribir un valor de PWM igual a valor en el actuador analógico 1.
  • write P2 valor: donde valor puede ser de 0 a 255. Escribir un valor de PWM igual a valor en el actuador analógico 2.

La aplicación interactiva en el PC es tipo consola en C# y debe tener:

  • Dos hilos.
  • Un hilo debe imprimir cada 100 ms el valor de un contador.
  • El otro hilo estará atento a los eventos del teclado producidos por el usuario.
  • Asigne una tecla a cada comando que será enviado al controlador.
  • Indicar si el controlador entendió o no entendió el comando, es decir, mostrar el NACK o el ACK (abajo la explicación de esto)

Nota

Para cualquiera de los comandos tipo write el controlador debe devolver los caraceres ACK si reconoce el comando y NACK si no los reconoce.

Debes decidir, dados los requisitos de la aplicación, si requieres introducir caracteres de nueva línea y/o retorno de carro. TEN PRESENTE que LOS LEDs deben funcionar SIEMPRE a 5 Hz y 10 HZ como se declaró previamente, ese decir, su funcionamiento no puede ser interrumpido por las operaciones del puerto serial