Osciloscopio casero

Osciloscopio casero

Durante mis estudios en ingeniería necesité en múltiples ocasiones un osciloscopio para poder trabajar con señales. Sin embargo, debido a los altos costos de estos equipos, no me los podía permitir. Aquí es donde el ingenio y algo de conocimiento me llevaron a usar Arduino y Processing para construir un osciloscopio casero.

El IDE de Arduino viene con múltiples ejemplos y aquí hay uno clave para este proyecto. Dentro de la sección de Ejemplos, encontramos la categoría Communication y ahí mismo está Graph.

El código de Arduino sería de esta manera:

  
void setup() {
  // inicializamos la comunicacion Serial
  Serial.begin(9600);
}

void loop() {
  // leemos el pin análogo A0 y lo enviamos por el puerto serial
  Serial.println(analogRead(A0));
  // esperamos un poco para que el conversor analogo a digital se establize
  //tras la última lectura
  delay(2);
}

Como podemos ver, es bastante sencillo. Partimos de inicializar el módulo serial, y de ahí nos mantenemos en un ciclo, en el cual leemos el dato que nos llega por el puerto análogo y este valor lo escribimos en el puerto serial a modo de string.

El código de Processing es el siguiente:

  
  import processing.serial.*;

  Serial myPort;        // creamos la variable del puerto serial
  int xPos = 1;         // inicializamos la posicion horizontal
  float inByte = 0;

  void setup () {
    // ajustamos el tamaño de la ventana:
    size(400, 300);

    // imprimiremos la lista de puertos disponibles
    println(Serial.list());
    // en la mayoría de los casos solo exitiría un elemento en el puerto sería (el arduino), pero de no ser así ajusta el valor 0, segun corresponda
    myPort = new Serial(this, Serial.list()[0], 9600);

    // espera hasta que tenga datos en el puerto serial
    myPort.bufferUntil('\n');

    // ajustar el color del backround:
    background(0);
  }

  void draw () {
    // ajustamos el color de la linea a dibujar:
    stroke(127, 34, 255);
    line(xPos, height, xPos, height - inByte);

    // al llegar al final del ancho de la pantalla, reiniciamos valores
    if (xPos >= width) {
      xPos = 0;
      background(0);
    } else {
      // incrementamos la poscion horizontal
      xPos++;
    }
  }

  void serialEvent (Serial myPort) {
    // leemos el caracter que viene del puerto seríal en codigo ASCII
    String inString = myPort.readStringUntil('\n');

    if (inString != null) {
      // eliminamos cualquier espacio en blanco
      inString = trim(inString);
      // usamos map para transformar los valores que vienen del puerto serial
    // de 0 hasta 1023 y los ajustamos al la altura de la ventana de 0 hasta height
    // que hemos configurado a 300px en el setup
      inByte = float(inString);
      println(inByte);
      inByte = map(inByte, 0, 1023, 0, height);
    }
  }    
  

Una vez hemos programado el Arduino, pasaremos a realizar el montaje de los componentes necesarios. Aquí vamos a usar únicamente un potenciómetro, de donde obtendremos nuestra lectura análoga.

conexion del potenciometro a la placa arduino en el puerto análogo A0

Al ejecutar todo junto, deberíamos tener un gráfico que responde a los cambios que realicemos en el potenciómetro, justo como se puede ver en el siguiente video.

0:00
/0:10

De momento tenemos una buena base de la cual podemos partir. Lo que sigue ahora es hacer unos ajustes dentro de Processing para que se parezca más a lo que veríamos dentro de un osciloscopio.

Para transformar el gráfico en una línea, he encontrado que la solución que da mejores resultados es almacenar el punto anterior de la coordenada X y la coordenada Y. Modificaremos la función line() para representar el gráfico que vemos en pantalla, de modo que los dos primeros parámetros que recibe sean el X y Y de la lectura anterior, y los dos siguientes parámetros los X y Y de la lectura actual.

Además, agregaremos una cuadrícula para obtener un resultado más “estético”. Dicho esto, ajustaremos el código de Processing de esta manera:

  
  import processing.serial.*;

  Serial myPort;        // creamos la variable del puerto serial
  int x = 1;            // inicializamos la posicion horizontal
  int prevX = 0;        // inicializamos la posicion horizontal previa
  float y, prevY = 0;   // inicializamos la posicion vertical y vertical previa
  int GRID_RESOLUTION = 10;  // la cantidad de lineas verticales y horizontales a dibujar
  void setup () {
    // ajustamos el tamaño de la ventana:
    size(400, 300);

    // imprimiremos la lista de puertos disponibles
    println(Serial.list());
    // en la mayoría de los casos solo exitiría un elemento en el puerto sería (el arduino), pero de no ser así ajusta el valor 0, segun corresponda
    myPort = new Serial(this, Serial.list()[2], 9600);

    // espera hasta que tenga datos en el puerto serial
    myPort.bufferUntil('\n');

    // invocamos la funcion initializeGraph, para cargar los valores por defecto
    initializeGraph();
  }

  void draw () {
    line(prevX, prevY, x, y);
    prevX = x;
    prevY = y;
      // al llegar al final del ancho de la pantalla, reiniciamos valores
    if (x >= width) {
      initializeGraph();
    } else {
      // incrementamos la posición horizontal:
      x++;
    }
  }

  void serialEvent (Serial myPort) {
    // leemos el caracter que viene del puerto seríal en codigo ASCII
    String inString = myPort.readStringUntil('\n');

    if (inString != null) {
      // eliminamos cualquier espacio en blanco
      inString = trim(inString);
        // usamos map para transformar los valores que vienen del puerto serial
    // de 0 hasta 1023 y los ajustamos al la altura de la ventana de 0 hasta height
    // que hemos configurado a 300px en el setup
      y = float(inString);
      println(y);
      y = map(y, 0, 1023, 0, height);
    }
  }
  
  void initializeGraph() {
      x = 1;
      prevX = 0;
      background(0);
      stroke(255);
      strokeWeight(1);
      for(int i = 1; i<= GRID_RESOLUTION; i++){
        float yResolution = width / GRID_RESOLUTION;
        float xResolution = height / GRID_RESOLUTION;
        float gridYPos = i * yResolution;
        float gridXPos = i * xResolution;
        line(gridYPos, 0,gridYPos, height);
        line(0, gridXPos,width, gridXPos);
      }
      strokeWeight(2);
      stroke(35, 127, 35);
  }
  

Una vez hechos estos cambios, obtendremos algo más cercano a lo que representaría un osciloscopio, lo cual podemos ver en el siguiente video.

0:00
/0:12

Llegados a este punto, ya tenemos algo bastante llamativo que se asemeja a un osciloscopio básico, sin embargo, esto sigue siendo una versión muy rudimentaria.

Aún no tenemos la capacidad de distinguir la frecuencia y amplitud de las ondas, y de hecho estamos limitados a la lectura de señales menores a 60 Hz.
Estas “limitaciones” son las que resolveremos en el próximo post.

Pues bien, muchas gracias por llegar hasta aquí. Te recuerdo suscribirte para recibir las notificaciones y puedas enterarte de todos los proyectos que iré realizando.