Ethan Printz
Tangible Course Search
Arduino and NodeJS-based combination physical-digital interface developed to improve the experience of looking through the courses offered by IMA and similar departments.
Overview
Course
Creative Computing
Term
Fall 2018
Role
Solo Project - Design and Development

Design Process

Background

Combining the work and experience gained from my different classes at NYU IMA, I created a combined physical and digital interface for the course search that used buttons, dials, and faders to filter through the most popular courses/majors available to IMA students. I felt that by detatching the user from the nebulousness of the poorly designed online course search and by then grounding the user in a physical reality they could more naturally explore their interests and pursuits. I also wanted to add an element of exploration and experimentation to the process, as natural discovery is lacking in the online system when you need to know what you're looking for in advance.

Filter Selection

I began with deciding on which filters would be best to include in the search:
possibleFilters.svg

User Flow

Next, I moved into figuring out the user flow within the project. There are two main phases, the selection phase and the search display phase. In the selection phase, the user decides which filters to use and adjusts those filter parameters. In the Display phase the user can scroll through the search results and choose to reset/redo the search.
flowchart.svg

Physical Construction

With the basic plan for the digital and combined framework for the project, I moved to working on the planning the physical arrangment of the dashboard and used that to determine how the digital interface would mimic it. I had some buttons, dials, and faders lying around from past projects, so those would form the basis of the arrangement. I found the wood board and dark acrylic lying around the ITP Shop discard area. It might not be the best quality wood, but it works well with a certain artistic 'work in progress' aesthetic that is a good representation of the major itself. I set up the layout in an illustrator file compatible with the laser cut in the ITP shop. Here is what the file looked like digitally
aiTemplate.png

And here is the resulting wood panel after laser cutting. I ended up having to flip the panel over and recut a second time because I had to transition from the 50W to the 75W laser midway through the cut, but I think the darker wood better suits the dark side panels anyway.
boardPrototype.jpg

Development

Background

With the physical prototype completed, I moved onto the digital software prototype. Like many of my other physical interaction projects, this prototype was constructed around a Node server running on a local laptop connected to the Arduino over USB Serial.

Server Setup

The server is setup as most other local NodeJS servers are and contains two different routes for data requests and webpage requests. Files are served froma public folder, courses are parsed from a local JSON file, and physical input data is handled within the app.js file itself in the Johnny Five code.

// Module Requirements
    var express = require('express');
    var path = require('path');
    var fs = require ('fs');
    var app = express();

// Get Courses
    var IMACourseFile = JSON.parse(fs.readFileSync('data/IMACourses.json'));


// Set public folder for client-side access
    app.use(express.static('public'));

// Send index.html at '/'   
    app.get('/', function(req, res){
        res.sendFile(path.join(__dirname + '/views/index.html'));
    });

//Send AJAX data stream at '/data'
    app.get('/data', function(req,res) {
        console.log(IMACourseFile);
        // Compile individual variables into object
            var dataToSendToClient = {
                IMACourseFile
            };
            
        // Convert javascript object to JSON
            var JSONdata = JSON.stringify(dataToSendToClient);
            
        //Send JSON to client
            res.send(JSONdata);
    });
 
//Set app to port 8080
    app.listen(8080);

//Log start of app
    console.log("App Started");

Hardware Interface

Below is the Johnny Five Code. It initializes the instance of the board and sets up the variables to be updated upon any of the button or dial states being changed.

var five = require("johnny-five");

    var board = new five.Board();

    board.on("ready", function() {
            // Major Dial
                var majorPotentiometer = new five.Sensor({
                    pin: majorPotentiometerPin,
                    freq: 250
                });
                    majorPotentiometer.on("data", function() {
                        //console.log("major Potentiometer: " + this.value);
                        majorPotentiometerValue = this.value;
                    });
            // Credit Dial
                var creditPotentiometer = new five.Sensor({
                    pin: creditPotentiometerPin,
                    freq: 250
                });
                    creditPotentiometer.on("data", function() {
                        //console.log("major Potentiometer: " + this.value);
                        creditPotentiometerValue = this.value;
                    });
            // Time Faders
                var timeBeforePotentiometer = new five.Sensor({
                    pin: timeBeforePotentiometerPin,
                    freq: 250
                });
                    timeBeforePotentiometer.on("data", function() {
                        //console.log("major Potentiometer: " + this.value);
                        timeBeforePotentiometerValue = this.value;
                    });
                var timeBeforePotentiometer = new five.Sensor({
                    pin: timeAfterPotentiometerPin,
                    freq: 250
                });
                    timeAfterPotentiometer.on("data", function() {
                        //console.log("major Potentiometer: " + this.value);
                        timeAfterPotentiometerValue = this.value;
                    });
            // Button
                var majorConfirmButton = new five.Button(majorConfirmButtonPin);
                    majorConfirmButton.on("press", function() {
                        //console.log("major PRESS!");
                        majorConfirmValue = true; 
                    });
                    majorConfirmButton.on("release", function() {
                        //console.log("major RELEASE!");
                        majorConfirmValue = false; 
                    });
                var unitConfirmButton = new five.Button(majorConfirmButtonPin);
                    unitConfirmButton.on("press", function() {
                        //console.log("major PRESS!");
                        unitConfirmValue = true; 
                    });
                    unitConfirmButton.on("release", function() {
                        //console.log("major RELEASE!");
                        unitConfirmValue = false; 
                    });
                var generalSearchButton = new five.Button(generalSearchButtonPin);
                    generalSearchButton.on("press", function() {
                        //console.log("SEARCH PRESS!");
                        generalSearchButtonValue = true; 
                    });
                    generalSearchButton.on("release", function() {
                        //console.log("SEARCH RELEASE!");
                        generalSearchButtonValue = false;
                    });
                // Buttons
                var generalResetButton = new five.Button(generalResetButtonPin);
                    generalResetButton.on("press", function() {
                        console.log("RESET PRESS!");
                        generalResetButtonValue = true; 
                    });
                    generalResetButton.on("release", function() {
                        console.log("RESET RELEASE!");
                        generalResetButtonValue = false;
                        majorConfirmLED.on();
                    });
    });