Week 13

Interface and Application Programming


Group assignment

  • Compare as many tool options as possible.
  • Individual assignment

  • Write an application that interfaces with an input and/or output device that you made, comparing as many tool options as possible.

  • Learning outcomes:


    Have you:

    Group assignment:

    Group assignment page

    For this week's assignment my instructor gave me three different tools to interface with an input/output.


    1. Trying processing:


    The first tool that we used was Processing. We wrote a script in Arduino and another one in Processing that will be communicating between them.
    The code in Arduino is the following. We are first declaring the values for the pins that we are using. Both rx and tx for the serial communication and then the pins of the LED and the button.
    We set the LED as an output and the button as an input and then what the loop id doing is: If its receiving data through the serial communication it will check the state of the LED. If this state is equal to 1 it will set the LED to high and otherwise it will set it to low. Also, when the button is pressed a message will be sent to the serial 'Button is pressed'.


    #include <SoftwareSerial.h>
    
    const int rx = PA0;
    const int tx = PA1;
    const int led = PA3;
    const int button = PA7;
    
    SoftwareSerial mySerial(rx, tx);
    
    
    void setup() {
      pinMode(led, OUTPUT);
      pinMode(button, INPUT_PULLUP);
      mySerial.begin(9600);
    }
    void loop() {
      if (mySerial.available() > 0) {
        char ledState = mySerial.read();
        if (ledState == '1') {
          digitalWrite(led, HIGH);
        }
        else if (ledState == '0') {
          digitalWrite(led, LOW);
        }
      }
      int buttonState = digitalRead(button);
      if ( buttonState == LOW) {
        mySerial.println("Button is pressed");
        delay(500);
      }
    }


    Then the code that we used in processing was the next one. What we are doing here is first to set the size of the window that will be open (300,300) and then creating the serial port to be able to read from it. As it was shown before, we are sending a message to the serial when pressing the button. This message will be read here. We use the draw function to draw what will appear in the window.

    import processing.serial.*;
    Serial myPort;
    String myText="";
    
    void setup(){
        size(300, 300);
        myPort = new Serial(this, "/dev/cu.usbserial-FTFMJ6MW", 9600);
        myPort.bufferUntil('n');
    }
    void serialEvent (Serial myPort){
        myText = myPort.readStringUntil('n');
        }
    void draw(){
        background(0,0,0);
        text(myText, 120, 120);
        textSize(26);
        myText="";
        if(mousePressed && (mouseButton == LEFT)){
            myPort.write('1');
            }
        if (mousePressed && (mouseButton == RIGHT)){
            myPort.write('0');
            }
    }
    
    

    When the button is pressed a message is displayed from processing.

    Board that I have been using for testing purposes.


    2. Python Web-based Serial Console using WebSockets:


    The second one that I tried was Python. I followed this tutorial to build an interactive web page for creating user interfaces to serial devices.
    The requirements for this tutorial are:

    1. I have a device that is communicating using a FTD interface via serial protocol to a computer.
    2. I will be receiving or sending data from sensors through the serial port.
    3. Manipulate the data in an HTML webpage using Javascript.
    4. I will use Web Sockets for having an open communication between the webpage and the web server.

    This is the architecture that is used in this tutorial: Image obtained from the site of the tutorial


    Zip with the files:

    The code that is used during this tutorial can be downloaded in this .zip file.

    1. serialworker.py: where you define the serial port that you are going to be reading data from and the functions that are required for reading and writing in the serial. The data that is comming in will be stored in a queue to be read and the output data in another one that will be sent.
    2. server.py: Using Tornado, where you define the port that you are going to be using and the web socket.
    3. index.html: where we describe the interface that the user is going to see.
    4. main.js: JavaScript code that using the Websocket will interact with the user.


    3. Trying JavaScript:


    For using JavaScript I had to install some packages previously.
    The first thing I installed was node, but instead of installing it directly from the site I downloaded it from nvm.

    1. I first installed nvm:
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.9/install.sh | bash.

    2. I checked that it had installed with this command command -v nvm.
    When executing this you should get 'nsv' in the terminal. The first time I did it I didn't get this message but then I closed and open a new terminal and it was working.

    3. Then I moved on to clone the git repository, and as I already have git I run:
    git clone https://github.com/creationix/nvm.git .nvm.

    4. I checked what version I was using : cd ~/.nvm + git checkout v0.33.9. When doing so I got HEAD is now at 1b14e6b... v0.33.9.
    I activated it through . nvm.sh.

    5. I installed node nvm install node. I checked what versions I had nvm ls and which one I was using node --version. As I was using the 9th one and I want to use the 6th one, I installed it nvm install 6.14.1.

    The three libraries that I will use are express, serial port and socket.io.

    For installing them I wrote in the console:

    npm i express
    npm i serialport
    npm i socket.io

    Once I had everything installed, my instructor gave me some examples for working with JavaScript and an input or an output. One of the files that you need to have is the one containing the modules.
    The structure of the files will be this one:


    node.button.c:

    In this file what we are doing is to, first, initialize the clock, the input (button) and the serial communication. Then the script will send a '1' whenever the button is pressed and a '2' when is not. The way of sending this numbers is :
    put_char(&serial_port, serial_pin_out, '1');
    put_char(&serial_port, serial_pin_out, 10);
    .
    We send the 1 directly and then the 10 corresponds in the ASCII code to a line break, as we will set the program to read when there is one.

    
    #include <avr/io.h>
    #include <util/delay.h>
    
    #define output(directions,pin) (directions |= pin) // set port direction for output
    #define input(directions,pin) (directions &= (~pin)) // set port direction for input
    #define set(port,pin) (port |= pin) // set port pin
    #define clear(port,pin) (port &= (~pin)) // clear port pin
    #define pin_test(pins,pin) (pins & pin) // test for port pin
    #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
    #define bit_delay_time 102 // bit delay for 9600 with overhead
    #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
    #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
    
    #define input_port PORTA
    #define input_direction DDRA
    #define input_pin (1 << PA7)
    #define input_pins PINA
    
    #define serial_port PORTA
    #define serial_direction DDRA
    #define serial_pins PINA
    #define serial_pin_out (1 << PA1)
    
    
    void put_char(volatile unsigned char *port, unsigned char pin, char txchar);
    
    
    int main(void) {
      static char chr;
      //
      // main
      //
      // set clock divider to /1
      //
      CLKPR = (1 << CLKPCE);
      CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
      //
      // initialize pins
      //
      set(serial_port, serial_pin_out);
      output(serial_direction, serial_pin_out);
      set(input_port, input_pin); // turn on pull-up
      input(input_direction, input_pin);
      //
      // main loop
      //
      while (1) {
        //
        // wait for button down
        //
        while (0 != pin_test(input_pins, input_pin))
          ;
        //
        put_char(&serial_port, serial_pin_out, '1');
        put_char(&serial_port, serial_pin_out, 10); // new line
    
        //
        // wait for button up
        //
        while (0 == pin_test(input_pins, input_pin))
          ;
        put_char(&serial_port, serial_pin_out, '2');
        put_char(&serial_port, serial_pin_out, 10); // new line
    
      }
    }
    
    
    void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
      //
      // send character in txchar on port pin
      //    assumes line driver (inverts bits)
      //
      // start bit
      //
      clear(*port, pin);
      bit_delay();
      //
      // unrolled loop to write data bits
      //
      if bit_test(txchar, 0)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 1)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 2)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 3)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 4)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 5)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 6)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      if bit_test(txchar, 7)
        set(*port, pin);
      else
        clear(*port, pin);
      bit_delay();
      //
      // stop bit
      //
      set(*port, pin);
      bit_delay();
      //
      // char delay
      //
      bit_delay();
    }
    
    
    

    server.js:

    In this file what we are doing is to create a local server that will make the connection between the board and the web. For doing so we first create the express variable and we set the port that we will be listening through (we can set one that we know that won't be used, like 1234). We also set the file where the .html, the libraries and the sketch.js are installed, in this case the public one.
    Next thing is to create the web socket. There is a function that will send a message to the console every time we have a new connection event. Is important to create the socket before defining the port as it will make use of it.
    We define the serial and the port that is used; establishing the properties that we want it to have like the speed and the moment when we want it to read, in this case after /n.
    Inicialization of the functions and then we define them.

    showPortOpen: this function is to check when a port is open. A message will be displayed in the console.

    sendSerialData: this function is sending the data that we are receiving from the previous code, the button one. In this case a condition is written just to know how it can be set but the only thing that will be needed to send the data is : io.emit('button', data);.

    showPortClose and showError: testing messages for when the port is closed or when we have an error.


    
    var express = require('express');
    var app = express();
    var server = app.listen(1234);
    app.use(express.static('public'));
    console.log("My server is running"); 
    
    var socket = require('socket.io');
    var io = socket(server);
    io.sockets.on('connection', newConnection);
    
    function newConnection(socket){
    	console.log('newConnection:' + socket.id);
    }
    
    var SerialPort = require('serialport');
    var myPort = new SerialPort("/dev/cu.usbserial-FTFMJ6MW", {
    	baudRate: 9600,
    	options: false,
    	parser: SerialPort.parsers.readline("\n")
    });
    
    myPort.on('open', showPortOpen);
    myPort.on('data', sendSerialData);
    myPort.on('close', showPortClose);
    myPort.on('error', showError);
    
    function showPortOpen() {
       console.log('port open. Data rate: ' + myPort.options.baudRate);
    }
     
    function sendSerialData(data) {
    	console.log(data);
        if (data==1){
       	io.emit('button', data);
       }
        if (data==2){
       	io.emit('button', data);
       }
      
    }
     
    function showPortClose() {
       console.log('port closed.');
    }
     
    function showError(error) {
       console.log('Serial port error: ' + error);
    }
    

    index.html:

    Here we are calling to the different files that we are going to be using and the libraries.


    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>Sockets Example</title>
        <script src="libraries/socket.io.js" type="text/javascript"></script>
        <script src="libraries/p5.js" type="text/javascript"></script>
        <script src="libraries/p5.dom.js" type="text/javascript"></script>
        <script src="libraries/p5.sound.js" type="text/javascript"></script>
        <script src="sketch.js" type="text/javascript"></script>
    
        <style>
          body {
            padding: 20px;
          }
        </style>
      </head>
      <body>
      </body>
    </html>
            

    sketch.js:

    In this file we are defining the socket to create the connection with the server, in this case a local server. Then what we do here is to call the socket that we have created before and set it to do a function, in this case socket.on('button', changeCircle);, this means that the button will do the changeCircle funtion. We define the function, in this case an ellipse will be changing colour when the button is pressed.


    var socket;
     
    function setup() {
      createCanvas(1024, 762);
      background(255);
      socket = io.connect('http://localhost:1234');
      
      socket.on('button', changeCircle);
      
      
      ellipse(100, 100, 155, 155);
    
    }
    
    function changeCircle(data) {
      if (data == 1){
        fill(51);
        ellipse(100, 100, 155, 155);
      }
      else if (data==2){
        fill(200);
        ellipse(100, 100, 155, 155);
      }
     }
    
    function draw() {
      
     }
             
             


    To start this server and work with this codes I went to the directory where the files were and I wrote node server.js in the console. At first I had some trouble as I was using the version v9.11.1 and I wanted to use the version 6: v6.14.1. I wrote nvm use v6.14.1 and then I had to reinstall the serial npm i serialport . And then I wrote again node server.js and it was working!.

    I opened a web explorer and I went to the server that I was using: http://127.0.0.1:1234/, clicked the button and the image was changing! :



    Individual assignment:


    For the individual assignment I will use the JavaScript example in order to generate a Webpage interface where you can communicate with a board that has a button.

    The aim is to show an image and change it when it receives an output from the board. When the button is pressed the image that I am displaying will change to another one. What I want to recreate is a person being slumped and changing the position to straight when it receives the signal.

    In the same way as the previous example I will have the following files:


    The programming of the board remained the same as I will use the 1s and 2s that it sends to the serial to read when to change the position. What I modified was the sketch.js.

    I read the reference of the image in the p5.js webpage:


    sketch.js

    var socket;
    var straight; 
    var slumped; 
     
    function preload() {
      straight = loadImage('straight.png');
      slumped = loadImage('slumped.png');
    }
    
    function setup() {
      createCanvas(1024, 762);
      background(255);
      socket = io.connect('http://localhost:1234');
      
      socket.on('button', showPic);
      image(straight, 200, 100);
    
      //ellipse(100, 100, 155, 155);
    
    
    }
    
    function showPic(data) {
        
        //fill('white');
    
      if (data == 1){
        image(straight,200,100);
      }
      else if (data==2){  
        image(slumped,200,100);
    
    
      }
    
     }
    
     function draw(){
    
     }
             
             


    4. Creating an App with App Inventor:


    For this week I also created an app with App inventor that I will include in my final project. For now I had only include some buttons for the Bluetooth connection and the same picture as I included in the previous example that will change when receiving a message from a board with a button. In the future this project will include:

    1. Bluetooth connection to the boards
    2. Information about the time that the user has spend in a bad / good position
    3. Number of times the motor has vibrated because the accelerometer has sense a bad inclination angle

    I went to the App inventorpage, and I created a new project. At first I started by knowing how it worked as I had never use it before. Then I starte to add the different buttons
    I added images for the buttons and underneath them I added labels where a message will be displayed when the action is taking place. The idea is that when the button is pressed, with the same code as before sending a 1 and a 2 when is pressed, the image will be changing.

    Then I went to the block design to set what each button was going to do. I had to do a bit of research to know how to work with the Bluetooth and I will use this on the Networking week.