Assignment 2b

Hello everyone!

I will walk you through about how to connect your Arduino (or Seeeduino Lotus) to p5.js and print out the results of your sound detection test. To learn more about the Signal Detection experiment you can visit this website:

The sound detection test will turn the light on and there will be either a beep from the buzzer or not. The beep will be determined totally random and you need to click the button whenever there is a beep.

Sound Detection Test

I am adding a link to the video of it, just to make the goal more clear:

The most important step is understanding the Arduino code. It does the experiment and prints out the results. Then, we will use p5.js to display the data. I am attaching my Arduino and p5.js code here.

I highly suggest completing “How To?” section to make sure you know how to setup your microprocessor and connect it to p5.js.

P.S: Do not forget that you need to close the serial monitor of your Arduino if you want the p5.js to work. There can’t be two programs trying to read an Arduino.

Step 1.

We need to create an Arduino code that does the test. Let’s pseudo code:

  1. We need to decide on the conditions
    • There are 4 conditions :
      • Condition 1: There is a beep and the user pushes the button. This is called ‘Hit’.
      • Condition 2: There is no beep and the user pushes the button. This is called ‘False Alarm’.
      • Condition 3: There is a beep and the user doesn’t push the button. This is called ‘Miss’.
      • Condition 4: There is no beep and the user doesn’t push the button. This is called ‘Correct Reject’.
  2. The code needs to print out the times each condition occurs. It also needs to print the total number of times it occurred.

Step 2.

Now, we have a plan, so let’s code!

Let’s initialize the variables we will use:

// Tahsin Can Sarlak - Tufts ENP 162 Fall 2020 Signal Detection Experiment

#include "Volume.h" // Include the Volume library

Volume vol; // Plug your speaker into the default pin for your board type which is D5:
// https://github.com/connornishijima/arduino-volume1#supported-pins

// Declares the pins for the buzzer, button, LED and
// the potentiometer. Make sure it matches with 
int beeper_pin = 5;
int but_pin = 6;
int led_pin = 4;
int poten_pin = A0;

// The state of the button
int state_but =0;

// The following variable will be used to decide if the buzzer will be turned on
int randNum;

// the frequency of the beeper
int frequency = 440;

// The volume levels
byte volume_low = 0;
byte volume_high = 125;

// The following variables will be used to keep track of 
// the total number of trials and the conditions
int trial = 1;
int hitrate = 0;
int falsealarm = 0;
int miss = 0;
int correctrej = 0;

Step 3.

Then, we need to setup the variables we will use, such as Serial.begin(9600) to print the variables so that p5.js can read.

void setup() {
  // This will start the serial where you can write sensor values
  Serial.begin(9600);

  // This initializes the pin modes
  pinMode(but_pin,INPUT);
  pinMode(led_pin,OUTPUT);
  pinMode(beeper_pin,OUTPUT);

  // Starts using the Volume library
  vol.begin();
}

Step 4.

Then, we need to turn on the light and create a random value which will determine if there will be a beep or not.

// This is the main function that collects data and prints out the results
void experiment(){
  // Turns on the light 
  digitalWrite(led_pin,HIGH);
  // Decides if the beeper will be turned on or off randomly
  randNum = random(1,3);

  // Uses the random number to decide if the beeper is going to beep or not
  if(randNum == 1){
    vol.tone(frequency, volume_low);
    vol.delay(1000);
    }
  else{
    vol.tone(frequency, volume_high);
    vol.delay(1000);
    }

Step 5.

Then, the user will either push the button or not and we will keep track of the times each condition occurs. I highly recommend pushing the button for a bit ( like a second or two), to make sure the Arduino has time to read your button.

  // reads the digital voltage value and will store it in the variable.
  // It will be either 0 or 1
  state_but = digitalRead(but_pin);
  vol.delay(1000);

  // This is the logic behind the experiment. 
  // If the beeper is on and the button is pushed, you are in the hit rate zone
  // If the beeper is on and the button is not pushed, you are in the miss zone
  // If the beeper is off and the button is pushed, you are in the false alarm zone
  // If the beeper is off and the button is not pushed, you are in the correct reject zone
  if( randNum == 2 && state_but == 1){
    hitrate++;
  }
  else if( randNum == 2 && state_but == 0){
    miss++;
  } 
  else if (randNum == 1 && state_but == 1){
    falsealarm++;
  }
  else if (randNum == 1 && state_but == 0){
    correctrej++;
  }

Step 6.

After that, we need to turn off the light and the buzzer for a short period of time, so that the user will get ready for the next round. Also, we need to print out the result to update p5.js.

// Turns off the LED and the beeper before the next trial
  digitalWrite(led_pin,LOW);
  vol.noTone();
  vol.delay(1000);
  // Prints out the sensor readings with a comma in between
  // p5.js will use this information to print out the number of times each condition is met
  Serial.print(hitrate);Serial.print(",");Serial.print(falsealarm);Serial.print(",");Serial.print(miss);Serial.print(",");Serial.print(correctrej);Serial.print(",");Serial.println(trial); 
}

Step 7.

Finally, we will create a while loop so that there will be a certain number of trials.

void loop() {
  // The code will run only 20 times since it can run only 
  // while the trial is less than 21
  while(trial<21){
    // Calls the function that does the experiment
    experiment();
    // Increases the number of trials each time the function is called
    trial++;
  }
}

This was it for the Arduino part! Now let’s upload the code and turn our p5.serialport app. You can enable “console enabled” and “read in ASCII” to see what Arduino is printing.

Step 8.

Now, we need to look at the Glitch code, which is so similar to reading 2 sensors example!

First, we need to have the necessary libraries.

 <head>
    <!-- These are the necessary libraries to use p5js, p5js serialport reading, p5js pubnub API -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
    <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.25.2.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/p5.serialserver@0.0.28/lib/p5.serialport.js"></script>
  </head>

Step 9.

Now, let’s have the important variables and setup the canvas and the serialport connection.

      // CHANGE THIS ONE WITH YOUR PORT NAME
      var portname = "COM16";
      // variable to hold an instance of the serialport library
      let serial;

      // for incoming serial data
      let inData;

      // to breakout the incoming data into five. Since there are four conditions and one to keep track of total time
      var sensor1, sensor2, sensor3, sensor4, sensor5;

      // The first function p5js runs. It runs only one time
      function setup() {
        // Creates the Canvas with the specific dimensions
        createCanvas(500, 500);
        // Calls the function to initialize and read the serialport - Arduino data from USB
        create_serial();
      }

Step 10.

When create_serial() is called, it takes the data and splits it into 5. Here how it does it.

      // Initializes the serailport, reads the data and sets the reading to variables sensor1 and sensor2.
      // Prints out the current updates on the console.log
      function create_serial() {
        serial = new p5.SerialPort(); // make a new instance of the serialport library
        serial.on("list", printList); // set a callback function for the serialport list event
        serial.on("connected", serverConnected); // callback for connecting to the server
        serial.on("open", portOpen); // callback for the 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
        // get the list of ports:
        function printList(portList) {
          // portList is an array of serial port names
          for (var i = 0; i < portList.length; i++) {
            // Display the list the console:
            console.log(i + " " + portList[i]);
          }
        }

        function serverConnected() {
          console.log("connected to server.");
        }

        function portOpen() {
          console.log("the serial port opened.");
        }

        function serialEvent() {
          // read a string from the serial port:
          var inString = serial.readLine();
          // check to see that there's actually a string there:

          if (inString.length > 0) {
            // convert it to a number:
            //split the values at each comma
            //  inData = Number(inString);
            var inDataArray = split(inString, ",");

           //set variables to the appropriate index of this array
            //turn these values from a string to a number
            sensor1 = Number(inDataArray[0]);
            sensor2 = Number(inDataArray[1]);
            sensor3 = Number(inDataArray[2]);
            sensor4 = Number(inDataArray[3]);
            sensor5 = Number(inDataArray[4]);
          }
        }

        function serialError(err) {
          console.log("Something went wrong with the serial port. " + err);
        }

        function portClose() {
          console.log("The serial port closed.");
        }
      }

Step 11.

I wanted to have a very simple display. So, my update_scene() basically prints out the condition and the number of times each condition occurs. Here is the simple code.

 // Updates the scene with the port reading
      function update_scene() {
        // Updates the background with a new one. This is how you clean the canvas each time
        background(255);
        // Prints out the reading from your microprocessor
        textSize(32);
        fill(0, 102, 153);

        text("Hit", 10, 30);
        text(sensor1, 10, 60);

        text("False-Alarm", 10, 100);
        text(sensor2, 10, 130);

        text("Miss", 10, 170);
        text(sensor3, 10, 200);

        text("Correct Reject", 10, 240);
        text(sensor4, 10, 270);

        text("Total Number of Trials", 10, 310);
        text(sensor5, 10, 340);
      }

Step 12.

Now when you run it, here is how it looks like:

Number of times each condition occurs

This was it! Now, you know the basic steps to build your own Sound Detection test.

Take care!

Design a site like this with WordPress.com
Get started