In this recitation, we did an exercise of serial communication: to send multiple datas from Arduino to Processing.
The goal was to make a Etch A Sketch. I started with circles first, hoping that they would be able to connect into a line and make that sand drawing effect:
This is the Processing code:
import processing.serial.*;
Serial myPort;
int n0;
int n1;
void setup() {
background(0);
size(600, 600);
printArray(Serial.list());
myPort=new Serial(this,Serial.list()[2], 9600);
}
void draw() {
while (myPort.available()>0) {
String line=myPort.readStringUntil(‘\n’);
if (line!=null) {
String[] fields=line.split(“,”);
if (fields.length >= 2) {
//printArray(fields);
print(fields[0].trim());
print(“,”);
println(fields[1].trim());
if (fields.length>=2) {
n0=int(fields[0].trim());
n1=int(fields[1].trim());
}
}
}
}
fill(225);
circle(n0,n1,5);
}
And this is the Arduino code:
void setup() {
Serial.begin(9600);
}
void loop() {
int sensor1 = analogRead(A0);
int sensor2 = analogRead(A1);
// int sensor3 = analogRead(A2);
// keep this format
Serial.print(sensor1);
Serial.print(“,”); // put comma between sensor values
Serial.println(sensor2);
//Serial.print(“,”);
// 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);
}
But the result is not as satisfying because the time gap the potentiometers create between the number changes. So I tried to use the line() function instead. The trick is to use px and py to define the starting point of the line, and put them inside the draw() function. Here is the new Processing code:
// 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.*;
String myString = null;
Serial myPort;
int NUM_OF_VALUES = 2; /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int[] sensorValues; /** this array stores values from Arduino **/
int x;
int y;
int px;
int py;
void setup() {
size(600, 600);
background(255);
setupSerial();
}
void draw() {
updateSerial();
printArray(sensorValues);
// use the values like this!
// sensorValues[0]
// fill(255);
// noStroke();
//// ellipse(sensorValues[0]/2,sensorValues[1]/2,50,50);
px=x;
py=y;
x=sensorValues[0]/2;
y=sensorValues[1]/2;
line(px, py, x,y);
stroke(0);
strokeWeight(3);
}
void setupSerial() {
printArray(Serial.list());
myPort = new Serial(this, Serial.list()[2], 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];
}
void updateSerial() {
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) {
for (int i=0; i<serialInArray.length; i++) {
sensorValues[i] = int(serialInArray[i]);
}
}
}
}
}
And here is the result:
Apart from the inconvenience of controlling the direction through two very wiggly potentiometers, it works quite well:)
The second part is to send data from Processing to Arduino. Here is the end result of the computer music instrument that I made:
The trick is to set another value to define the turning on of the instrument, else the buzzer would keeps singing and never shuts up:(
The Arduino code is here:
#define NUM_OF_VALUES 3 /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
/** DO NOT REMOVE THESE **/
int tempValue = 0;
int valueIndex = 0;
/* This is the array of values storing the data from Processing. */
int values[NUM_OF_VALUES];
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
getSerialData();
// add your code here
// use elements in the values array
// values[0]
// values[1]
if (values[2] == 1) {
tone(8,values[0],values[1]);
}
}
//recieve serial data from Processing
void getSerialData() {
if (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 ‘,’:
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
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;
//if the char c from Processing is character ‘e’
//it is signalling for the Arduino to send Processing the elements saved in the values array
//this case is triggered and processed by the echoSerialData function in the Processing sketch
case ‘e’: // to echo
for (int i = 0; i < NUM_OF_VALUES; i++) {
Serial.print(values[i]);
if (i < NUM_OF_VALUES – 1) {
Serial.print(‘,’);
}
else {
Serial.println();
}
}
break;
}
}
}
The Processing code is as follows:
import processing.serial.*;
int NUM_OF_VALUES = 3; /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
Serial myPort;
String myString;
// This is the array of values you might want to send to Arduino.
int values[] = new int[NUM_OF_VALUES];
void setup() {
size(500, 500);
background(0);
printArray(Serial.list());
myPort = new Serial(this, Serial.list()[ 2 ], 9600);
// check the list of the ports,
// find the port “/dev/cu.usbmodem—-” or “/dev/tty.usbmodem—-”
// and replace PORT_INDEX above with the index 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;
}
void draw() {
background(0);
fill(255);
circle(mouseX,mouseY,20);
// changes the values
values[0]=mouseX;
values[1]=mouseY;
if (keyPressed && key == ‘ ‘) {
values[2]=1;
} else {
values[2]=0;
}
// sends the values to Arduino.
sendSerialData();
// This causess the communication to become slow and unstable.
// You might want to comment this out when everything is ready.
// The parameter 200 is the frequency of echoing.
// The higher this number, the slower the program will be
// but the higher this number, the more stable it will be.
echoSerialData(200);
}
void sendSerialData() {
String data = “”;
for (int i=0; i<values.length; i++) {
data += values[i];
//if i is less than the index number of the last element in the values array
if (i < values.length-1) {
data += “,”; // add splitter character “,” between each values element
}
//if it is the last element in the values array
else {
data += “n”; // add the end of data character “n”
}
}
//write to Arduino
myPort.write(data);
}
void echoSerialData(int frequency) {
//write character ‘e’ at the given frequency
//to request Arduino to send back the values array
if (frameCount % frequency == 0) myPort.write(‘e’);
String incomingBytes = “”;
while (myPort.available() > 0) {
//add on all the characters received from the Arduino to the incomingBytes string
incomingBytes += char(myPort.read());
}
//print what Arduino sent back to Processing
print( incomingBytes );
}
Additional Assignment:
This is the Processing code for the Assignment:
import processing.serial.*;
String myString = null;
Serial myPort;
int NUM_OF_VALUES = 2;
int[] buttonValues;
int preButtonValue0 = 0; //initial value of the 1st button is 0
int preButtonValue1 = 0;
boolean star1Display = false;
boolean star2Display = false; //initial state of the start display is false
void setup() {
size(500, 500);
background(0);
setupSerial();
}
void draw() {
updateSerial();
printArray(buttonValues);
//refresh background color
background(0);
//whenever the button is pressed & the value us different from the previous value
if (buttonValues[0] == 1 && buttonValues[0] != preButtonValue0) {
star1Display = !star1Display;
}
if (buttonValues[1] == 1 && buttonValues[1] != preButtonValue1) {
star2Display = !star2Display;
}
`
//two shapes of starts
if (star1Display == true) {
pushMatrix();
translate(width*0.5, height*0.5);
rotate(frameCount / 400.0);
star(0, 0, 80, 100, 40);
popMatrix();
}
if (star2Display == true) {
pushMatrix();
translate(width*0.8, height*0.5);
rotate(frameCount / -100.0);
star(0, 0, 30, 70, 5);
popMatrix();
}
//previous value of button is also changing so we update it as well
preButtonValue0 = buttonValues[0];
preButtonValue1 = buttonValues[1];
}
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()[ 2 ], 9600);
myPort.clear();
myString = myPort.readStringUntil( 10 );
myString = null;
buttonValues = new int[NUM_OF_VALUES];
}
void updateSerial() {
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) {
for (int i=0; i<serialInArray.length; i++) {
buttonValues[i] = int(serialInArray[i]);
}
}
}
}
}
This is the Arduino code:
void setup() {
Serial.begin(9600);
}
void loop() {
int button1 = digitalRead(9);
int button2 = digitalRead(10);
// keep this format
Serial.print(button1);
Serial.print(“,”); // put comma between sensor values
Serial.print(button2);
Serial.println();
// too fast communication might cause some latency in Processing
// this delay resolves the issue.
delay(100);
}
And this is the video of the effect:
This is a picture of the circuit: