Categories
Interaction Lab

Recitation 8: Serial Communication

Exercise 1: Make a Processing Etch-A-Sketch

code:

Arduino

// IMA NYU Shanghai
// Interaction Lab
// For sending multiple values from Arduino to Processing


void setup() {
  Serial.begin(9600);
}

void loop() {
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = analogRead(A0);
  int sensor2 = analogRead(A1);
//  int sensor3 = analogRead(A2);

  // send the values keeping this format
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[];      /** this array stores values from Arduino **/

String myString = null;
Serial myPort;

void setup() {
  size(500, 500);
  setupSerial();
}

void draw() {
  background(229,187,129);
  getSerialData();
  printArray(sensorValues);
  noStroke();
  fill(161,23,21);

 float val1 = sensorValues[0];
 float val2 = sensorValues[1];
 circle(val1, val2, 100);
}

void setupSerial() {
  //printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 1 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
  
    sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

I didn’t get into trouble when I let the ball move. But when I change it into a line, the problem of background happened again. I didn’t find this problem and tried to modify other elements. Finally, I found that I need to delete the background() in the void draw to let the line appear on the screen.

code

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[]; /** this array stores values from Arduino **/
String myString = null;
Serial myPort;
float x = random (width);
float y = random (height);

void setup() {
  size(500, 500);
  setupSerial();
   background(229,187,129);
}

void draw() {
 
  getSerialData();
  printArray(sensorValues);
  
 float lx = map ( sensorValues[0],0,1023,0,500);
 float ly = map ( sensorValues[1],0,1023,0,500);
 stroke(161,23,21);
 strokeWeight(3);
 line (lx,ly, x, y);
 
 x = lx;
 y = ly;
 
 
}

void setupSerial() {
  //printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 1 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
  
    sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

Exercise 2

 

Code

Arduino

#include <Servo.h>
#define NUM_OF_VALUES_FROM_PROCESSING 3    /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/

Servo myservo; 

/** DO NOT REMOVE THESE **/
int tempValue = 0;
int valueIndex = 0;

/* This is the array of values storing the data from Processing. */
int processing_values[NUM_OF_VALUES_FROM_PROCESSING];


void setup() {
  Serial.begin(9600);

  myservo.attach(9);
}

void loop() {
  getSerialData();
  
     if (processing_values[0] == 1){
      myservo.write(180);
      delay(100);
     }else{
      myservo.write(0);
    }
}

//receive serial data from Processing
void getSerialData() {
  while (Serial.available()) {
    char c = Serial.read();
    //switch - case checks the value of the variable in the switch function
    //in this case, the char c, then runs one of the cases that fit the value of the variable
    //for more information, visit the reference page: https://www.arduino.cc/en/Reference/SwitchCase
    switch (c) {
      //if the char c from Processing is a number between 0 and 9
      case '0'...'9':
        //save the value of char c to tempValue
        //but simultaneously rearrange the existing values saved in tempValue
        //for the digits received through char c to remain coherent
        //if this does not make sense and would like to know more, send an email to me!
        tempValue = tempValue * 10 + c - '0';
        break;
      //if the char c from Processing is a comma
      //indicating that the following values of char c is for the next element in the values array
      case ',':
        processing_values[valueIndex] = tempValue;
        //reset tempValue value
        tempValue = 0;
        //increment valuesIndex by 1
        valueIndex++;
        break;
      //if the char c from Processing is character 'n'
      //which signals that it is the end of data
      case '\n':
        //save the tempValue
        //this will b the last element in the values array
        processing_values[valueIndex] = tempValue;
        //reset tempValue and valueIndex values
        //to clear out the values array for the next round of readings from Processing
        tempValue = 0;
        valueIndex = 0;
        break;
    }
  }
}

Processing

import processing.serial.*;
int NUM_OF_VALUES_FROM_PROCESSING = 1;  
int processing_values[] = new int[NUM_OF_VALUES_FROM_PROCESSING]; 
Serial myPort;
String myString;

float x;
float speedX;
float s;

void setup() {
  fullScreen();


  background(0);
  speedX = 5 ;
  
  setupSerial();
}
void draw() {
  background(147,224,255);
  noStroke();
  fill(255,66,93);
  circle (x, 350, 100);
  x= x+speedX;
  if (x > width || x < 0) {
    speedX = -speedX;
  }
   if (x > width) {// hit the left wall
    processing_values[0] = 1;
  } else  {
    processing_values[0] = 0;
}
  sendSerialData();
}
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.clear();
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;
}
void sendSerialData() {
  String data = "";
  for (int i=0; i<processing_values.length; i++) {
    data += processing_values[i];
   
    if (i < processing_values.length-1) {
      data += ","; // add splitter character "," between each values element
    }
    else {
      data += "\n"; // add the end of data character linefeed "\n"
    }
  }
  myPort.write(data);
  print(data); // this prints to the console the values going to arduin0
}

When I made the Processing code, I found my motor didn’t move and only the bouncing ball worked. In addition, the number in the console of Processing is always 0. I asked Professor Godoy for help and she solved the coding problem by changing the “if (x > width-s/2)” into “if (x > width)” so that it represents 1 when the ball touches the side of the screen. And we also found I connect the circuit in the wrong way and it stopped the motor. (The right order is brown is ground, red is 5V and orange is special pin)

Homework

Code 

Arduino

// IMA NYU Shanghai
// Interaction Lab
// For sending multiple values from Arduino to Processing
int button1 = 4;
int button2 = 8;

int count1;
int count2;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(button1) == HIGH){
    count1 = count1 +1;
  }
    if (digitalRead(button2) == HIGH){
    count2 = count2 +1;
  }
  Serial.print(count1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(count2);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

Processing

// IMA NYU Shanghai
// Interaction Lab
// For receiving multiple values from Arduino to Processing

/*
 * Based on the readStringUntil() example by Tom Igoe
 * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
 */

import processing.serial.*;


int NUM_OF_VALUES_FROM_ARDUINO = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int sensorValues[];      /** this array stores values from Arduino **/

String myString = null;
Serial myPort;

void setup() {
  size(600, 600);

  setupSerial();
  
}

void draw() {
    background(0);
  getSerialData();
  printArray(sensorValues);
 if (sensorValues[0] % 2 == 1) {
    pushMatrix();
    translate(width*0.3, height*0.3);
    rotate(frameCount / 200.0);
    star(0, 0, 30, 70, 5);
    popMatrix();
  }
  if (sensorValues[1] % 2 == 1) {
    pushMatrix();
    translate(width*0.7, height*0.7);
    rotate(frameCount / 200.0);
    star(0, 0, 80, 100, 40);
    popMatrix();
  }

}

void star(float x, float y, float radius1, float radius2, int npoints) {
  float angle = TWO_PI / npoints;
  float halfAngle = angle/2.0;
  beginShape();
  for (float a = 0; a < TWO_PI; a += angle) {
    float sx = x + cos(a) * radius2;
    float sy = y + sin(a) * radius2;
    vertex(sx, sy);
    sx = x + cos(a+halfAngle) * radius1;
    sy = y + sin(a+halfAngle) * radius1;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[3], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = '\n'  Linefeed in ASCII
  myString = null;

  sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO];
}

void getSerialData() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = '\n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

At first, I write this Arduino code.

// Interaction Lab
// For sending multiple values from Arduino to Processing
int button1 = 4;
int button2 = 8;


void setup() {
  Serial.begin(9600);
}

void loop() {
  // to send values to Processing assign the values you want to send
  //this is an example
  int sensor1 = digitalRead(4);
  int sensor2 = digitalRead(8);
  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(sensor2);
//  Serial.print(",");  // put comma between sensor values
//  Serial.print(sensor3);
  Serial.println(); // add linefeed after sending the last sensor value

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(100);

  // end of example sending values
}

 And I found only when I press the button, the star appears. The requirement is “when you press button 1 once, star 1 will appear on the canvas, and when you press button 1 once again, star 1 will disappear.”

So I decided to use count to solve this problem and when the number of pressing times is odd, the stars appear and the number is even, the stars disappear. 

I research that sound can work as input and generate creative outputs. Music can draw be shown on the screen and let it become more visible.

Here is the example I have found. https://processing.org/tutorials/sound/#example-5-6-audio-analysis

 

/**
 * Processing Sound Library, Example 5
 *
 * This sketch shows how to use the FFT class to analyze a stream
 * of sound. Change the number of bands to get more spectral bands
 * (at the expense of more coarse-grained time resolution of the spectrum).
 *
 * Load this example with included sound files from the Processing Editor:
 * Examples > Libraries > Sound > Analysis > FFTSpectrum
 */

import processing.sound.*;

// Declare the sound source and FFT analyzer variables
SoundFile sample;
FFT fft;

// Define how many FFT bands to use (this needs to be a power of two)
int bands = 128;

// Define a smoothing factor which determines how much the spectrums of consecutive
// points in time should be combined to create a smoother visualisation of the spectrum.
// A smoothing factor of 1.0 means no smoothing (only the data from the newest analysis
// is rendered), decrease the factor down towards 0.0 to have the visualisation update
// more slowly, which is easier on the eye.
float smoothingFactor = 0.2;

// Create a vector to store the smoothed spectrum data in
float[] sum = new float[bands];

// Variables for drawing the spectrum:
// Declare a scaling factor for adjusting the height of the rectangles
int scale = 5;
// Declare a drawing variable for calculating the width of the
float barWidth;

public void setup() {
  size(640, 360);
  background(255);

  // Calculate the width of the rects depending on how many bands we have
  barWidth = width/float(bands);

  // Load and play a soundfile and loop it.
  sample = new SoundFile(this, "beat.aiff");
  sample.loop();

  // Create the FFT analyzer and connect the playing soundfile to it.
  fft = new FFT(this, bands);
  fft.input(sample);
}

public void draw() {
  // Set background color, noStroke and fill color
  background(125, 255, 125);
  fill(255, 0, 150);
  noStroke();

  // Perform the analysis
  fft.analyze();

  for (int i = 0; i < bands; i++) {
    // Smooth the FFT spectrum data by smoothing factor
    sum[i] += (fft.spectrum[i] - sum[i]) * smoothingFactor;

    // Draw the rectangles, adjust their height using the scale factor
    rect(i*barWidth, height, barWidth, -sum[i]*height*scale);
  }
}

 

 

 

 

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *