Skip to content

15. Interface and Application Programming

This week, I used my board and code from inputs week along with processing to make a display for the data coming in.

The final file can be found here

Processing Test Drawing

I had done a bit of processing prior to fab academy, but I hadn’t used it in a while, so I started with just getting a good framework for the drawing and display aspect of the code. I ended up with the following code:

int xdim = 400;
int ydim = 400;

void setup() {
  size(400, 400);
  background(200);
}

int val1 = 0;
int val2 = 0;
int val3 = 0;

void draw() {
  int rectTotLen = 300;
  int rectWid = 50;
  background(200);
  int distBtwn = (xdim - (rectWid * 3)) / 4;
  makeInnerRect((xdim - rectTotLen) / 2, distBtwn, val1, rectWid, rectTotLen);
  makeInnerRect((xdim - rectTotLen) / 2, distBtwn * 2 + rectWid, val2, rectWid, rectTotLen);
  makeInnerRect((xdim - rectTotLen) / 2, distBtwn * 3 + rectWid * 2, val3, rectWid, rectTotLen);
  ++val1;
  val1 = val1 % rectTotLen;
  val2 = (val2 + 2) % rectTotLen;
  val3 = (val3 + 3) % rectTotLen;
  delay(10);
}

void makeInnerRect(int x, int y, int val, int wid, int totLen) {
  noStroke();
  fill(0, 0, 255);
  rect(x, y, val, wid);
  fill(255, 0, 0);
  rect(x + val, y, totLen - val, wid);
}

I used variables to store x and y dimensions to better be able to reference it in the main loop, but I do not use them for the size function in setup because it gives and error whenever I try to.

The values are global variables since the display only updates at the end of the draw function, so it would be impossible to use local variables and loop through the changes to them with a delay as only the end result would show once it reaches the end of the draw function.

The makeInnerRect function I wrote made it easier to make a rectangle representing a value with just a few inputs rather than doing the whole process every time. It makes 2 side to side rectangles, one blue one red, to show the value as the lengths of the 2 sections.

Processing Test with Serial

Having gotten the display mostly set up, I then set my sights to getting serial data into processing. I referenced both the example provided by the processing reference and this site. I ended up with the following code:

import processing.serial.*;

Serial mySerial;
String inputStr;

void setup() {
  mySerial = new Serial(this, "COM13", 9600);
  mySerial.clear();
  mySerial.readStringUntil('\n'); //throw out first reading in case start in middle of transmission
}

void draw() {
  if (mySerial.available() > 0) {
    inputStr = mySerial.readStringUntil('\n');
    if (inputStr != null) {
      print(inputStr);
      int[] readings = int(split(inputStr, ' '));
      for (int i = 0; i < 3; ++i) {
        println(readings[i]);
      }
    }
  }
}

I used the processing serial library, and I set it up with the COM port of my board (this may change depending on the port used) and a baud rate of 9600, and I throw out the first reading in case the board was in the middle of a transmission when processing started.

In the draw function, I check if there is serial available and read a line if it is. I then check to make sure that the string is not null which I thought I wouldn’t need to do since the if statement guarantees that there is input to be read and all the data coming from the input board has a new line at the end, but it was giving null pointer errors without the check. I later realized that since my input board code printed each reading separately and a separate new line character at the end, and it had a delay at the end of each loop, making it send data slower than processing is checking for data, processing was checking at times when some of the data had sent but not the new line character at the end.

I printed the raw data input and then split it into integers for each reading. I then looped through and printed each reading. I used i < 3 instead of i < readings.length because the split was returning a junk fourth value that would always be 0.

Putting it all Together

I put together the 2 previous programs to both read serial data and display it.

import processing.serial.*;

Serial mySerial;
String inputStr;
int xdim = 400;
int ydim = 400;

void setup() {
  size(400, 400);
  background(200);
  mySerial = new Serial(this, "COM13", 9600);
  mySerial.clear();
  mySerial.readStringUntil('\n'); //throw out first reading in case start in middle of transmission
}

void draw() {
  if (mySerial.available() > 0) {
    inputStr = mySerial.readStringUntil('\n');
    if (inputStr != null) {
      int[] readings = int(split(inputStr, ' '));
      for (int i = 0; i < 3; ++i) {
        readings[i] += 200;
        readings[i] *= 300;
        readings[i] /= 400;
      }
      int rectTotLen = 300;
      int rectWid = 50;
      background(200);
      int distBtwn = (xdim - (rectWid * 3)) / 4;
      makeRect((xdim - rectTotLen) / 2, distBtwn, readings[0], rectWid, rectTotLen);
      makeRect((xdim - rectTotLen) / 2, distBtwn * 2 + rectWid, readings[1], rectWid, rectTotLen);
      makeRect((xdim - rectTotLen) / 2, distBtwn * 3 + rectWid * 2, readings[2], rectWid, rectTotLen);
    }
  }
  delay(10);
}

void makeRect(int x, int y, int val, int wid, int totLen) {
  noStroke();
  fill(0, 0, 255);
  rect(x, y, val, wid);
  fill(255, 0, 0);
  rect(x + val, y, totLen - val, wid);
  stroke(0);
  strokeWeight(5);
  line(x + totLen / 2, y, x + totLen / 2, y + wid);
}

Wiring

The arduino only provides 3.3v power to the microcontroller and input on my input week board with the Rx and Tx pins of the input going to the Tx and Rx pins of an FTDI chip with everything sharing a ground.

I made a few changes to both of the smaller pieces of code in this final part.

I no longer was printing the values from the sensor, and I was doing some processing of them to get them in the 0 to 300 range from a -200 to 200 range.

I removed the val1, val2, and val3 variables and replaced them with readings from the sensor, and I renamed the makeInnerRect function to just makeRect. In this function, I also added a line in the middle to show where 0 is since there are negative numbers coming in.

Group Work

Our group work for this week can be found here.

I worked on trying out tkinter with python and learned how to do so with a combination of the following sites: https://www.geeksforgeeks.org/python-tkinter-tutorial/, http://academy.cba.mit.edu/classes/input_devices/mag/TLE493D/hello.TLE493D.t412.py, https://devtut.github.io/python/python-serial-communication-pyserial.html#initialize-serial-device, and https://stackoverflow.com/a/69509753.

I found it to be good for full program control (or rather as much control as python would give) rather than having the setup and draw functions being run in the background implicitly, but the way it organizes things with widgets is a bit confusing and can clutter up code with a ton of widget objects.


Last update: June 2, 2022