Skip to content

14. Interface & Application Programming

I. Individual Assignment

My plan for this week’s assignment was to program an interface that would interact with a switch, phototransistor and LED located on a board I had previously produced. I kept things simple as I didn’t have a lot of time to experiment.

Processing

1. Programming an Interface

I first focused on designing an interface containing a set number of elements whose characteristics would change when certain conditions are met. My aim was to define a programming logic for what I was aiming to achieve. With that goal in mind, I wrote a short program through which I would create a set number of boxes whose colour could be modified by clicking when the mouse pointer would be located within their boundaries.


Interface Demo


  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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
import processing.serial.*;

Serial myPort;

// Initialisation of Variables used throughout.


int nBoxes = 3;

int canvasW = 1080; int canvasH = 1080;

int rectW = 400; int rectH = 200;

int rectX = 300; int rectY = 200; int Yoffset = 50;

int[] rectXcoordinates = new int[nBoxes];

int[] rectYcoordinates = new int[nBoxes];

boolean[] rectState = new boolean[nBoxes];

boolean[] rectHoverCondition = new boolean[nBoxes];

boolean clickedMouse = false;

String[] ButtonIndicators = {"LED Continuous", "LED Flicker", "Phototransistor"};


void setup() {
  size(1000,1080);
  background(248,248,255);
  noStroke();

    // List all the available serial ports
    // if using Processing 2.1 or later, use Serial.printArray()
    println(Serial.list());

    // I know that the first port in the serial list on my mac
    // is always my  Arduino, so I open Serial.list()[0].
    // Open whatever port is the one you're using.
    myPort = new Serial(this, Serial.list()[4], 9600);
    // don't generate a serialEvent() unless you get a newline character:
    myPort.bufferUntil('\n');

  for (int i = 0; i < nBoxes; i = i+1) {
    println(i);
    fill(0);  
    rect(rectX,rectY,rectW,rectH,9);
    rectXcoordinates[i] = rectX;
    rectYcoordinates[i] = rectY;
    rectY += rectH + Yoffset;
  }
  println(rectXcoordinates);
}

void draw() {

    for (int j = 0; j < nBoxes; j = j+1){
      if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == false && clickedMouse == true){
        onState(rectXcoordinates[j], rectYcoordinates[j], ButtonIndicators[j]);
        rectState[j] = true;
        clickedMouse = false;
      }
      else if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == true && clickedMouse == true){
        offState(rectXcoordinates[j], rectYcoordinates[j],ButtonIndicators[j]);
        rectState[j] = false;
        clickedMouse = false;
      }
    }

}



void mouseClicked() {
  clickedMouse = !clickedMouse;
}


void onState(int x, int y, String ind){

      // Rectangle color modification.
      fill(128,237,153);
      rect(x,y,rectW,rectH,9);



      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to On");
      println("");
}

//
void offState(int x, int y, String ind){

      // Rectangle color modification.
      fill(0);
      rect(x,y,rectW,rectH,9);

      // Text related commands.


      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to Off");
      println("");
}

2. Receiving Commands from an external PCB

Using a tutorial by Sparkfun as reference, I worked on communicating commands between the Processing interface and an external PCB. I worked with a board I had produced for the Electronics Design week, which contained a button switch, a programmable LED and a phototransistor.

ED_PCB

I added some text to the interface. Each button was now assigned a specific function I will later program into the board, and had an ON and OFF state. One would turn the LED on, the other would make it flicker, and the last would activate readings from the phototransistor. Should the phototransistor readings be activated, then the LED’s intensity would vary with the value emitted by the phototransistor. If they are deactivated, the LED’s intensity would be set to its highest value of 255.


Interface_Buttons

Updated Interface with Descriptive Text


My aim was to use the button switch located on the board to set all buttons on the interface to their OFF state. Serial communication can be used to send/receive orders to/from a PCB. Processing has a pre-installed library designed for that specific purpose. I first had to initialise the library by going to Sketch/Import Library/Serial.

1
2
3
import processing.serial.*;

Serial myPort; // Create object from Serial class
Next, I had to specify which port to open through a specific command. To do so, I needed to obtain the name of all available ports, which I did using the following command:

1
println(Serial.list());
Using the below command, I initialised the serial port.

1
myPort = new Serial(this, "Port Name", Baud Rate);

Finally, I added a function which would constantly listen to the serial port and register a value sent by the board when the button is clicked. The Processing sketch responsible for the control of the interface was also modified to set all button states to off when a change in value occurred.

1
2
3
void serialEvent (Serial myPort) {
  resetButton = boolean (myPort.readStringUntil ( '\n' ) ) ;  // Changing
}
A simple if loop was added to the Arduino code I had written for the [Embedded Programming] week. This loop would send a “1” through the serial comm line when the board’s button was clicked. The complete Arduino and Processing programs can be found below.

1
2
3
if (PuSwState == LOW){
  Serial.println(1);
}


 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
// Pin Assignment

const int PuSwitchPin = 0; // PU Switch
const int LEDPin = 6; // LED
const int PTransPin = 7; // PhotoTransistor

// Initialisation of Variables
int PuSwState = 0;
int PuSwStatus = 0;
int PTransState = 0;
int LEDintensity = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LEDPin,OUTPUT);
  // initialize digital pin Switch pin as an intput.
  pinMode(PuSwitchPin, INPUT);
  pinMode(PTransPin, INPUT);

  Serial.begin(9600); //Initialising the serial monitor for debugging purposes

}

// the loop function runs over and over again forever
void loop() {

  PuSwState = digitalRead(PuSwitchPin);
  PTransState = analogRead(PTransPin);

  if (PTransState > 0){
    LEDintensity = map(PTransState, 0, 1023, 0, 255);
  } else {
    LEDintensity = 255;        
  }

  analogWrite(LEDPin, LEDintensity);// turn the LED on (HIGH is the voltage level)

  if (PuSwState == LOW){
    Serial.println(1);
    delay(500);
  }
}
  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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import processing.serial.*;

Serial myPort;

// Initialisation of Variables used throughout.


int nBoxes = 3;

int canvasW = 1080; int canvasH = 1080;

int rectW = 400; int rectH = 200;

int rectX = 300; int rectY = 200; int Yoffset = 50;

int[] rectXcoordinates = new int[nBoxes];

int[] rectYcoordinates = new int[nBoxes];

boolean[] rectState = new boolean[nBoxes];

boolean[] rectHoverCondition = new boolean[nBoxes];

boolean clickedMouse = false; boolean resetButton = false;

String[] ButtonIndicators = {"LED Continuous", "LED Flicker", "Phototransistor"};



void setup() {
  size(1000,1080);
  background(248,248,255);
  noStroke();

    // List all the available serial ports
    // if using Processing 2.1 or later, use Serial.printArray()
    println(Serial.list());

    // I know that the first port in the serial list on my mac
    // is always my  Arduino, so I open Serial.list()[0].
    // Open whatever port is the one you're using.
    myPort = new Serial(this, "/dev/cu.usbserial-FT9P04G3", 9600);
    // don't generate a serialEvent() unless you get a newline character:
    myPort.bufferUntil('\n');

    println(myPort);

  for (int i = 0; i < nBoxes; i = i+1) {
    println(i);
    fill(0);  
    rect(rectX,rectY,rectW,rectH,9);
    rectXcoordinates[i] = rectX;
    rectYcoordinates[i] = rectY;
    rectY += rectH + Yoffset;
  }
  println(rectXcoordinates);
}

void draw() {
    if (resetButton == false){
          offState(rectXcoordinates[0], rectYcoordinates[0],ButtonIndicators[0]);
          rectState[0] = false;
          offState(rectXcoordinates[1], rectYcoordinates[1],ButtonIndicators[1]);
          rectState[1] = false;
          offState(rectXcoordinates[2], rectYcoordinates[2],ButtonIndicators[2]);
          rectState[2] = false;
          resetButton = true;
    }
    for (int j = 0; j < nBoxes; j = j+1){
      if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == false && clickedMouse == true){
        onState(rectXcoordinates[j], rectYcoordinates[j], ButtonIndicators[j]);
        rectState[j] = true;
        clickedMouse = false;
      } else if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == true && clickedMouse == true){
        offState(rectXcoordinates[j], rectYcoordinates[j],ButtonIndicators[j]);
        rectState[j] = false;
        clickedMouse = false;
      }
    }
}

void serialEvent (Serial myPort) {
  resetButton = boolean (myPort.readStringUntil ( '\n' ) ) ;  // Changing
  println(resetButton);
}

void mouseClicked() {
  clickedMouse = !clickedMouse;
}


void onState(int x, int y, String ind){

      // Rectangle color modification.
      fill(128,237,153);
      rect(x,y,rectW,rectH,9);

      // Text related commands.
      fill(0); // Text color.
      textSize(30); // Font Size

      textAlign(CENTER);
      text(ind, x, y+rectH/4, rectW, rectH); // Text coordinates and contents.
      text("ON", x, y+2*rectH/4, rectW, rectH); // Text coordinates and contents.


      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to On");
      println("");
}

//
void offState(int x, int y, String ind){

      // Rectangle color modification.
      fill(0);
      rect(x,y,rectW,rectH,9);

      // Text related commands.
      fill(255); // Text color.
      textSize(30); // Font Size
      textAlign(CENTER);
      text(ind, x, y+rectH/4, rectW, rectH); // Text coordinates and contents.
      text("OFF", x, y+2*rectH/4, rectW, rectH); // Text coordinates and contents.


      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to Off");
      println("");
}

3. Sending Commands to an external PCB

Finally, I added a few commands to both the Arduino and the processing programs in order to control the PCB from the interface, as demonstrated below.



In short, the exchange of commands is achieved through UART commms. When either Processing or the PCB receive data on the Serial lines, this data is read and interpreted. The section above detailed how commands are sent from the PCB to the processing interface. For sending commands from the interface to the PCB I derived a simple logic in which a specific value would be sent to the board when one of the interface buttons was clicked. This value would inform the PCB of the current state of the interface buttons, which would in turn triger a change of state in the LED or phototransistor, as decribed in the below table.

LED Button PhotoTransistor Button Value Sent LED State Phototransistor Reading
OFF OFF 0 OFF OFF
ON ON 1 ON Active
ON OFF 2 ON OFF
OFF ON 3 OFF Active

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    if (val == 0){
      PTransState = 0;
      LEDintensity = 0;
    } else if(val == 1){
      PTransState = analogRead(PTransPin);
      LEDintensity = map(PTransState, 0, 1023, 0, 255);
    } else if(val == 2){
      PTransState = 1;
      LEDintensity = 255;
    } else if(val == 3){
      PTransState = analogRead(PTransPin);
      LEDintensity = 0;
    }

 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
48
49
50
51
52
53
54
55
56
57
// Pin Assignment

const int PuSwitchPin = 0; // PU Switch
const int LEDPin = 6; // LED
const int PTransPin = 7; // PhotoTransistor

// Initialisation of Variables
int PuSwState = 0;
int PuSwStatus = 0;
int PTransState = 0;
int LEDintensity = 0;
int val = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LEDPin,OUTPUT);
  // initialize digital pin Switch pin as an intput.
  pinMode(PuSwitchPin, INPUT);
  pinMode(PTransPin, INPUT);

  Serial.begin(9600); //Initialising the serial monitor for debugging purposes

}

// the loop function runs over and over again forever
void loop() {

  PuSwState = digitalRead(PuSwitchPin);


  if (Serial.available()) { // If data is available to read,

      val = Serial.read(); // read it and store it in val
  }

  if (val == 0){
    PTransState = 0;
    LEDintensity = 0;
  } else if(val == 1){
    PTransState = analogRead(PTransPin);
    LEDintensity = map(PTransState, 0, 1023, 0, 255);
  } else if(val == 2){
    PTransState = 1;
    LEDintensity = 255;
  } else if(val == 3){
    PTransState = analogRead(PTransPin);
    LEDintensity = 0;
  }

  analogWrite(LEDPin, LEDintensity);// turn the LED on (HIGH is the voltage level)

  if (PuSwState == LOW){
    Serial.println(1);
    delay(500);
  }
}
  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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import processing.serial.*;

Serial myPort;

// Initialisation of Variables used throughout.


int nBoxes = 2;

int canvasW = 1080; int canvasH = 1080;

int rectW = 400; int rectH = 200;

int rectX = 300; int rectY = 200; int Yoffset = 50;

int[] rectXcoordinates = new int[nBoxes]; int[] rectYcoordinates = new int[nBoxes];

int[] rectState = new int[nBoxes];

boolean[] rectHoverCondition = new boolean[nBoxes]; boolean clickedMouse = false;

boolean resetButton = false;

String[] ButtonIndicators = {"LED Continuous", "Phototransistor", "LED Flicker"};



void setup() {
  size(1000,1080);
  background(248,248,255);
  noStroke();

    // List all the available serial ports
    // if using Processing 2.1 or later, use Serial.printArray()
    println(Serial.list());

    // I know that the first port in the serial list on my mac
    // is always my  Arduino, so I open Serial.list()[0].
    // Open whatever port is the one you're using.
    myPort = new Serial(this, "/dev/cu.usbserial-FT9P04G3", 9600);
    // don't generate a serialEvent() unless you get a newline character:
    myPort.bufferUntil('\n');

    println(myPort);

  for (int i = 0; i < nBoxes; i = i+1) {
    println(i);
    fill(0);  
    rect(rectX,rectY,rectW,rectH,9);
    rectXcoordinates[i] = rectX;
    rectYcoordinates[i] = rectY;
    rectY += rectH + Yoffset;
  }
  println(rectXcoordinates);
}

void draw() {
    if (resetButton == false){
          for (int i = 0; i < nBoxes; i = i+1){
              offState(rectXcoordinates[i], rectYcoordinates[i],ButtonIndicators[i]);
              rectState[i] = 0;
          }
          resetButton = true;
    }
    for (int j = 0; j < nBoxes; j = j+1){
      if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == 0 && clickedMouse == true){
        onState(rectXcoordinates[j], rectYcoordinates[j], ButtonIndicators[j]);
        rectState[j] = 1;
        clickedMouse = false;
      } else if ((mouseX>rectXcoordinates[j]) && (mouseX<(rectXcoordinates[j]+rectW)) && (mouseY>rectYcoordinates[j]) && (mouseY<(rectYcoordinates[j]+rectH)) && rectState[j] == 1 && clickedMouse == true){
        offState(rectXcoordinates[j], rectYcoordinates[j],ButtonIndicators[j]);
        rectState[j] = 0;
        clickedMouse = false;
      }
    }

    // Sending commands to Arduino
    if(rectState[0] == 0 && rectState[1] == 0){
      myPort.write(0);
    }else if(rectState[0] == 1 && rectState[1] == 1){
      myPort.write(1);
    }else if(rectState[0] ==  1 && rectState[1] == 0){
      myPort.write(2);
    }else {
      myPort.write(3);
    }
}

void serialEvent (Serial myPort) {
  resetButton = boolean (myPort.readStringUntil ( '\n' ) ) ;  // Changing
}

void mouseClicked() {
  clickedMouse = !clickedMouse;
}


void onState(int x, int y, String ind){

      // Rectangle color modification.
      fill(128,237,153);
      rect(x,y,rectW,rectH,9);

      // Text related commands.
      fill(0); // Text color.
      textSize(30); // Font Size

      textAlign(CENTER);
      text(ind, x, y+rectH/4, rectW, rectH); // Text coordinates and contents.
      text("ON", x, y+2*rectH/4, rectW, rectH); // Text coordinates and contents.


      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to On");
      println("");
}

//
void offState(int x, int y, String ind){

      // Rectangle color modification.
      fill(0);
      rect(x,y,rectW,rectH,9);

      // Text related commands.
      fill(255); // Text color.
      textSize(30); // Font Size
      textAlign(CENTER);
      text(ind, x, y+rectH/4, rectW, rectH); // Text coordinates and contents.
      text("OFF", x, y+2*rectH/4, rectW, rectH); // Text coordinates and contents.


      // Debugging.

      println("Debug - Mouse is Pressed in box - Switching to Off");
      println("");
}

4. Summary

No issues encountered here. The interface and PCB control were kept simple and it wasn’t hard to implement what I was looking for.

Node-Red [To Do]

I was very limited in time this week and didn’t have time to learn to use Node-Red. However, I am definitely interested in determining how it can be used in a remote network to control the flow of data and display relevant information, when desired to a user. I’ll try to do this after the project presentations.

MIT App Inventor [WiP - for Final Project]

I essentially tried to create an app that would Post data from my phone to the ESP web server I programmed on an ESP32 during the Networking and Communications week. Should I succeed, I would then be able to broadcast my phone’s GPS coordinates to my final project’s base station, and essentially track my phone instead of a module designed separately. I succeeded.

1. Setting up the workflow.

MIT’s app inventor has a companion app for iOS and android that can be used to emulate the designed application.

II. Group assignment

For this week’s group assignment, I’ll be comparing Processing and the MIT App Inventor.

Processing

Processing is described as being “a graphical library and development environmnet designed for teaching non-programmers the fundementals of computer programming in a visual context”. Its language is built around Java, to which it adds additional simplifications through aliases, mathematical functions and operations.

Processing’s own interface is almost identical to that of the Arduino IDE. This made it a quite familiar environment to work in and rather easy to pick up.

Interfaces

The structure of the language itself is also similar to that of Arduino. Variable definition, library imports, function definition and logic functions work in the same manner. Further to this, processing can work with Serial ports to send and receive commands or data which allows for external components to control and interface, or be controlled by an interface.

From my experience using it, I must say that it does achieve its principal goal rather well. The framework does not feel limiting for simple implementations, and the community resources make it even more accessible. However, I am not in a position to say how efficient it might be to use in order to deploy more complex visual interfaces.

MIT App inventor

This tool is impressive in its simplicity. First of all, the interface itself is well designed as it allows for specific elements to be added easily through its “designer” module. Second, manipulating on screen elements


Last update: May 25, 2021