syllabus

Arduino Serial Output Lab

This week we covered Serial Communication, which is how you would send data from a microcontroller to your personal computer. Review the week 5 lecture slides, and note any question you have.

In class we did the Async Serial Output Lab I (pp. 11 - 21). We’ve added in more instructional materials in the slides. Review the lab, and move on to try the Async Serial Output Lab II (pp. 22 - 30), where you’d send two values from the Arduino. After establishing communication, try to change a couple parameters, or combine your own sketch you made for the p5.js Lab with some Serial interaction! Work with your midterm group if it makes it easier.

You can also follow this guide:

Async Serial Output Lab II

Arduino

Bill of materials: Arduino board x1, Breadboard x1, Pushbutton x1, Potentiometer (the small blue thing) x1, 10k resistor x1, jumper wires a couple

schematic

Most of you will need to be able to send two or more values in the future. In this case, Serial.write() wouldn’t be able to fit much information, you need to use Serial.print().

In the Arduino code, print out the values one by one with Serial.print(), each seperated by comma Serial.print(", ");, and remember to add a new line by using Serial.println() on your last value. In this example, we have two values to send out.

Full Arduino code:

int potPin = A0;
int potVal;
int btnPin = 2;
int btnState;

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

void loop() {
  potVal = analogRead(potPin);
  btnState = digitalRead(btnPin);
  Serial.print(potVal);
  Serial.print(", ");
  Serial.println(btnState);
}

In the Serial monitor, it would print as below

serial monitor

Connection and p5.js

Open p5.serialcontrol, and keep it open. CLOSE THE ARDUINO SERIAL MONITOR as only one Serial port can be accessed at once. Scan your ports to make sure the Serial port that connects to your Arduino is appearing in the Info panel. You’re all set to communicate between Arduino and p5.js as long as you keep the app open.

We’re using this p5 sketch for this example. Everything is setup already, but in order for you to use it, remeber to replace the portName variable (line 2) with your own port.

port name on line 2

What’s happening in the code? Let’s break it down.

The > right underneth the Play / Stop buttons expands into your root files. You should see three:

You were only able to use p5 functions because there was a p5.js library <script>referenced in the index.html file – and now to use Serial control, we’d also have to add a p5.serialport <script> that supports these functions. So navigate to the index.html file, and see that under the <head> tag and below the other scripts, I’ve added in:

<script
  language="javascript"
  type="text/javascript"
  src="https://cdn.jsdelivr.net/npm/p5.serialserver@latest/lib/p5.serialport.js"
></script>

Now we’re all set up for a p5.js sketch that can talk to other devides via Serial!

Back to the sketch.js file. We have a setup() function, in which we call createCanvas() to create a canvas 400px x 400px big.

function setup() {
  createCanvas(400, 400);
}

In setup() we also need to add in callback functions related to serial setups, which will be executed later in the code. You don’t have to worry about them for now.

function setup() {
  createCanvas(400, 400);

  // Serial setup

  serial = new p5.SerialPort(); // make a new instance of the serialport library
  serial.on("list", printList); // callback to list all the ports
  serial.on("connected", serverConnected); // callback for connecting to server
  serial.on("open", portOpen); // callback to check port opening
  serial.on("data", serialEvent); // callback for when new data arrives
  serial.on("error", serialError); // callback for errors
  serial.on("close", portClose); // callback for the port closing

  serial.list(); // list the serial ports
  serial.open(portName); // open a serial port
}

Most data receiving and formatting happens in the serialEvent() function later in the code (line 67-82).

Now, what we’re getting from the Arduino are: a number between 0-1023, a comma and space, and a nother number between 0-1. And every set of new data shows up in a new line, as seen in the serial monitor before:

serial monitor

In the serialEvent() function, the program is reading the incoming Serial information as strings, a sequence of characters, until it gets to carriage return (\r) and newline (\n). These characters are at the end of each new reading because we sent serial.println(), which automatically sends out a carriage return byte and a newline byte. It’s an easy way to tell the program: hey it’s a new line, that means we got through to the end of the current reading, now onto the next one.

After making sure there’re strings to be read, we split the incoming string by commas, which we sent through serial.println(), seperating both readings. We split them up, and put both them in an array called inputs. From here, we can access those numbers by calling their array and position: inputs[0] and inputs[1]. We covered array briefly last week, refer back to last week’s slides for a refresher.

function serialEvent() {
  // read a String from serial port
  // until you get carriage return and newline:
  let inString = serial.readStringUntil("\r\n"); // store in a variable
  //check to see that there's actually a string:
  if (inString.length > 0) {
    let inputs = split(inString, ","); // split the value by commas, put into array
    if (inputs.length > 1) {
      // if there are two or more elements
      console.log(inputs[0], inputs[1]); // print the input values
    }
  }
}

then we could call our specific inputs for this sketch, and store them in variables. This is completely optional and can be done in the draw() function too, but I like to keept them defined before sending them there.

potVal = map(inputs[0], 0, 1023, 0, width); // first element in the array
pressed = inputs[1]; // second element in the array

In the draw() function, the sketch gets drawn out, and we can add conditions to use the Serial data as interactive devices.

function draw() {
  background(0);
  // change ball color on press
  if (pressed == 1) {
    // if pressed, color it blue
    fill(color(0, 0, 255));
  } else {
    // if not pressed, color it yellow
    fill(color(255, 255, 0));
  }
  noStroke();
  ellipse(width / 2, height / 2, potVal, potVal); // now draw the ellipse, size based on pot value
  // draw a line based on pot value
  stroke(255);
  strokeWeight(4);
  line(5, 5, potVal, potVal);
}

Hope it worked for you!! Try to change a couple parameters, or combine your own sketch you made for the p5.js Lab with some Serial interaction! You can always copy the entire Serial section (line 48 onwards) and just change the serialEvent() function. Work with your midterm group if it makes it easier.