carlosor@andrew.cmu.edu – Intro to Physical Computing: Student Work Spring 2021 https://courses.ideate.cmu.edu/60-223/s2021/work Intro to Physical Computing: Student Work Sun, 23 May 2021 15:55:55 +0000 en-US hourly 1 https://wordpress.org/?v=5.6.13 You’ve Got Mail! by the Oaks: Final Documentation https://courses.ideate.cmu.edu/60-223/s2021/work/youve-got-mail-by-the-oaks-final-documentation/ Fri, 14 May 2021 00:19:39 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=13552 INTRODUCTION

As a team, we (Carlos Ortega and Amelia Lopez) worked with Annie Verchick  to develop a gadget suited for her unique needs. Checking mail was always a challenge for Annie, and at one point she had six weeks worth of mail piled up. Included in that mail was time-sensitive information and money which she missed due to not checking the mail on time. Clearly, this was a problem for her that desperately needed a solution.

We ended up designing a simple, elegant device so that Annie could see at a glance if she received mail in her mailbox without having to go outside. From inside her house, she could check the lights on a wall mounted box or read from an LCD display also on the box which displayed either “you’ve got mail” or “no mail.” Further on in the documentation we discuss the specifics of the design. For previous designs/problems we considered solving for Annie, please see our interview documentation linked here where we spend time explaining why we settled on solving this problem for Annie and what our initial sketches looked like.

WHAT WE BUILT

Our device, “You’ve Got Mail”, checks if there is mail in our client’s mailbox. It does this through 2 or 3 sensors we place strategically inside the mailbox Annie has mounted to her wall outside. These sensors tell us if there is something inside the mailbox. Inside her house we’ve built another box which has two lights (1 green and 1 red) and a screen display. If there’s mail, the screen display changes to say “you’ve got mail” or “no mail” if there is no mail. The light turns green when there’s mail or stays red when there is no mail. The box inside is powered through a wall outlet so the display and lights are always on. 

Images of final device. The upper left is the mini-box that would go inside the house; the remaining images are a demo of her mailbox with the sensors inside. The lower left shows what’s inside the mail box (3 sets of break-beam sensors positioned across from each other: top-bottom, left- right, and left-right). The lower right shows a an isometric view of of the box with an engraving, and the upper right picture shows a front view of the mailbox with an envelope engraving and a slit for the mail to go through

Video of the final product:

Narrative Sketch

It’s a cloudy, but bright-feeling day in the Sierra. The snow covers the seldom-used front porch and the wall-mounted mailbox next to the wooden door, which has also been touched by the snow. Meanwhile, Annie and her dog grab the leash and take their time out the side door for an exciting morning in the snow. 

Just as they leave, the mailman has been on the opposite side of the house, stuffing the mailbox with the long-awaited family letters and packages. At last, when Annie and her dog return through the old side door, the green light on Annie’s front wall catches her eye. She reads on the newly-installed screen the words “Mail status: You’ve got mail!”

As she eagerly opens the door to open her letters, she sees the mailman on his way back, and they exchange a sweet good morning.

HOW WE GOT HERE (PROTOTYPES AND PROCESS)

Prototype 1: Carlos Ortega

How can we activate the mail checker on command, and from any distance? This prototype uses a wireless remote and an infrared receiver; the mission was to learn how to program them.

How it works: pressing any button on the remote turns (both) lights on. They automatically turn off after 5 seconds. The user can turn the lights off sooner than 5 seconds with the power button on the remote. The final product would decide which single light to turn on (instead of both), but that would come later.

In action: the remote turns the lights on and off.

Circuit reports back at every remote control click.

Close-up of the circuit.

Prototype 1 in action

(GIF of prototype 1 in action. WordPress may fail to display…)

Intermediate steps
Left: programming the remote and remote receiver. Right: turning on lights

The lights wouldn’t stop flashing!

The code reports back which part of the program is currently executing.

The most significant feedback we received: don’t use the remote. The remote came out of our assumption that the mailbox was out in Annie’s yard, far away from her porch, and down a flight of stairs. We were surprised to find out that the mailbox was actually mounted on the wall. Instead, we decided to also mount our gadget on the same wall, on the interior side. The  remote, then, would have been overkill, so we decided to scrap that feature.

Based on some feedback, we were also going to add an arcade-style push button for the dog to check the mail with his paw. It was just for fun, but we scrapped that extra feature too before we even started implementing it.

Even so, prototype 1 really did answer the question of how do a remote control and a receiver work? The remote sends pulses of infrared light of different durations. When combining pulses of different lengths, we can recognize those patterns, and encode information; each button press sends out a different pattern. The infrared sensor receiver detects the pulses, sends them to the Arduino, and the Arduino can then extract the information from those pulses.

We had to borrow some pre-existing code (called a library) in order to read these patterns from the remote. It was a surprise to see that the example code on our class website used a previous version of the library, and was therefore outdated. I had to look at the documentation for the newer version.

Process

Using a screen for the first time!
Left: not enough cables! Right: plugged straight into a breadboard.

Left: LCD screen working. Right: LCD screen not working.

Mysteriously, the only cause was uploading the code to the Arduino again! With no changes whatsoever to the code! The solution was just turning the Arduino off and back on again.

Designing electrical box in CAD

(Process continued in Amelia’s process section)

Prototype 2: Amelia Lopez

This prototype was designed to help answer the design question: can we use break-beam sensors to ensure mail is accurately detected in the mailbox every time?

To answer this, I designed 2 boxes: one of which served as a representation of Annie’s mailbox where I could put the break-beam sensors, and the second box served as the one which would be inside and had the LCD display as well as 2 LED lights. We were confident the break beam sensor was an ideal device for this project because they work by having an emitter send out a beam of IR light and a receiver receives the light from across. When something interrupts the light, the beam is broken and we know that there is some object in the way, preferably mail.

This is my mailbox prototype. I designed the box using AUTOCAD and then laser cut it out of carboard in order to get the design right. The left image shows me testing the output of the sensor by putting in a sheet of paper. The upper right image shows one set of break beams I positioned in the box (top-bottom). The bottom right shows a front view of the box.

This is my mini-box prototype. The left image shows the box sealed, the center image shows a top view of the box with the LCD screen and LEDs. The right image shows a view inside the box with the Arduino and wires attached.

There are also earlier iterations of my prototype which accomplish the same idea but look more “rough”

This picture shows an early version of the prototype where I was testing the break beam. The upper 3 images show the LED/LCD status when the break beam is unbroken/ no mail. The bottom 3 images shows the LED/LCD status when the break beam is broken/mail

 

In my prototyping process, I found that break beams are a great sensor for this particular problem but I needed more than one break beam to ensure the device accurately detected every piece of mail which was surprising. If I positioned the mail too far right or too far left, I discovered that my break beam going from top-bottom didn’t catch that piece of mail. To solve this, I added 2 more sets of break beams (for a total of 3 break beams) both going from left-right but positioned either far left or far right.

Another part of the prototyping process was designing the mini-box that would go inside Annie’s house. We were looking to simplify and clean up the design which meant using a caliper to measure the size of the LCD display and diameter of the LEDs. To mount the LCD, originally we were going to use screws on either corner but found that it took away from the cleanness of the design and settled on using tape on the bottom of the display to hold it together instead so that the front view would only consist of the LEDs and LCD.

In terms of feedback from our client, she was very happy with the design and pushed us to integrate a wall-power adapter instead of batteries in order to power the device. She has many outlets in her home, and this was a simpler solution for her. This ultimately made the design of the mini-box smaller because we didn’t have to worry about storing a battery and caused us to add a square-sized hole to the final design of the box box in order for the adapter to fit through.

Process (continued)

Project management for final build

We stuck to the plan surprisingly well. Making a Gantt chart is immensely useful for project management, as it gives you a super concise way of gauging where you are relative to everything you’ve done and still have to do.

CONCLUSIONS AND LESSONS LEARNED

From the final critique, there were several key findings we discovered from the feedback process. One included the fact that our simple approach to the mini-box was very effective. One critiquer stated “The concept is simple and easy to understand. It also seems to work consistently well.” which we felt was fair. Another positive reviewer stated “the red/green was very simple but effective, really liked the final product!” which we enjoyed seeing. Overall, it seemed that the clean design fulfilled its purpose and wasn’t overly complicated.

In terms of what could’ve made the design more robust, reviewers stated “maybe send a notification to Annie’s phone when she gets mail”, “how easy would it be to read the red / green notification LED from a  distance? Maybe an audible alert could help with that” and “it looks like the feedback display is connected to the device by wires so maybe making it connect over Bluetooth or Wifi might improve the flexibility of the device” which are all points we would think about changing in a future iteration of the device. Sending a notification to Annie’s phone would certainty help adapt the device and would probably get rid of the mini-box inside her home so that she would just see the status of her mail through her phone.

A favorite piece of feedback from the critique session (it was given verbally, so it’s hard to quote but this was the idea):

It looks too much like a security system. It could be much more user-friendly; less austere.

I completely agree. We could solve this by making the electronics box rounder, maybe even out of some other material, in another color. The idea would be to make the gadget more huggable.

Working remotely is really difficult, especially working completely off campus, and even more so in different time zones! It was difficult to work without the amazing resources CMU makes available. It makes me so much more grateful for being at CMU!

Having one WordPress editor made it really hard to write the documentation. After having worked on two separate builds, we developed our own unique take on the project, with our own different process. Sometimes it was difficult to progress as a team, rather than as two individuals. Especially while making the documentation, and WordPress’s limitations exacerbated that.

In terms of lessons learned, I believe we were both pleasantly surprised how such a small and simple solution could impact Annie’s daily routine. Not having a disability makes you unaware of all that you take advantage of, and simply walking up to your mailbox everyday is a convivence not everyone is afforded with ease. When we were showing our design to other clients of the class, they reasoned with this hardship and stated that our solution was simple yet effective. Annie described life as being incredibly DIY; she constantly has to find her own solutions to her own challenges, that professional therapists can’t solve. This is why it was so important for Annie to work with a group of very creative young students who are able to solve these problems. We are privileged to have been able to design a solution to help Annie with this task and hope it improves her life.

For next time, we could use a smaller Arduino, like the Nano, for example. For such a simple task, the Arduino Uno feels like overkill. However, the box is already a good size for user interface purposes, so the box itself might have to stay about the same size in order to keep it “huggable.”

Last important lesson: keep it simple.

TECHNICAL DETAILS

Mailbox and gadget concept art

Schematic and Block diagram

Code

/*

  60-223, Final Project
  Amelia Lopez (aelopez)
  Updated by Carlos Ortega on May 2

  Description:
     Reads from 2 breakbeams;
     if at least 1 of them is broken, turns on a green LED
     and updates an LCD screen.
     Turns on the red LED otherwise.

  Challenges:
     Incorporating the IR receiver code would've been challenging,
     but fortunately we didn't use that code at all.
     Deciding how many break beams to incorporate

  Next time:
     Use enumeration type for lcdStatus instead of strings.
     Another version of the code uses 3 breakbeams instead of 2.

  Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   13            input     BREAK BEAM SENSOR 1
   12            input     BREAK BEAM SENSOR 2
   ~11           input     INFRARED REC. PIN 
   ~10           output    GREEN LED 
   ~9            output    RED LED 
   7             output    LCD RS
   6             output    LCD E
   ~5            output    LCD D4
   4             output    LCD D5
   ~3            output    LCD D6
   2             output    LCD D7

   (digital PWM~)


*/
#include <LiquidCrystal.h> 


//DECLARING ARDUINO PINS
const int SENSOR_PIN1 = 13;
const int SENSOR_PIN2 = 12;
const int GREEN_PIN = 10;
const int RECV_PIN = 11;
const int RED_PIN = 9;
const int LCD_RS = 7;
const int LCD_E = 6;
const int LCD_D4 = 5;
const int LCD_D5 = 4;
const int LCD_D6 = 3;
const int LCD_D7 = 2;

//VARIABLE FOR BREAK BEAM
int sensorState1 = 0;
int sensorState2 = 0;
String lcdStatus = "waiting"; 

//DECLARING INTS FOR LCD WAITING TIMES
const int WAIT_TIME = 300;
unsigned long timeVariable = 0;

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);



void setup() {
  //output pins
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);

  //input pins
  pinMode(SENSOR_PIN1, INPUT_PULLUP);
  pinMode(SENSOR_PIN2, INPUT_PULLUP);
  digitalWrite(SENSOR_PIN1, HIGH); // turn on the pullup
  digitalWrite(SENSOR_PIN2, HIGH); // turn on the pullup

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  //print constant letters on screen
  lcd.setCursor(2, 0);
  lcd.print("Mail status: ");

  Serial.begin(9600);
}

void loop() {
  sensorState1 = digitalRead(SENSOR_PIN1);
  sensorState2 = digitalRead(SENSOR_PIN2);

  // turn green LED on if beam is broken (there's mail):
  if (sensorState1 == LOW || sensorState2 == LOW) {
    Serial.println("Broken");
    digitalWrite(GREEN_PIN, HIGH);
    digitalWrite(RED_PIN, LOW);
    lcdStatus = "You've got mail!";
    Serial.println("sensorState1: ");
    Serial.println(sensorState1);
    Serial.println("sensorState2: ");
    Serial.println(sensorState2);
  }
  //turn red LED on (there's no mail)
  else {
    Serial.println("Unbroken");
    digitalWrite(RED_PIN, HIGH);
    digitalWrite(GREEN_PIN, LOW);
    lcdStatus = "    No mail     ";
  }

  //UPDATING VALUES ON LCD
  if (millis() - timeVariable > WAIT_TIME) {
    //updating input sensor value
    lcd.setCursor(0, 1);
    lcd.print(lcdStatus);

    timeVariable = millis();
  }
}

fast forward symbol from: 410160-middle.png

]]>
Gestural Midi Controller https://courses.ideate.cmu.edu/60-223/s2021/work/gestural-midi-controller/ Fri, 09 Apr 2021 21:47:59 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12814

At last, a way to produce electronic music with physical gestures. Rotate your hand and wiggle a joystick to manipulate sound in four distinct ways.

Overview

At last, a way to produce electronic music with physical gestures. Rotate your hand and wiggle a joystick to manipulate sound in four distinct ways.

Relative proportion of Gesture Controller

Relative proportion of Joystick Controller

 

Graphical user interface and midi translator between Arduino and Logic Pro

Process Images and Review

The Controller was going to have two modes: Performance Mode and Wand Mode

In Performance Mode, all 3 axes of the accelerometer would control 3 different parameters. Side to side for Pitch Bend and vibrato, front and back for Modulation, and up and down for Expression.

In Wand Mode, a single parameter would react to the overall motion.

In both modes, the joystick would control two parameters with the X and Y axes, but they would control slightly different parameters depending on the mode.

I had two major problems. In the first one, I had to calculate the velocity and position based on the acceleration readings, for all 3 axes.

Code from the old physics suite: getDeltTime(), noiseGated(), and getRestingState()

The problem is that accelerometer readings are noisy and give data even when not moving. This random data was accumulating in the velocity calculations and causing my variables to overflow, and thus the position calculations were even worse.

I tried noise gating the data when the accelerometer was not moving (i.e. when the readings were at 0), and only letting the data through when above a certain threshold. But above that threshold, the readings were still noisy and inaccurate.

I scrapped almost all of that code.

Demonstrating the new gestures the controller will respond to. (Far left) Printing accelerometer rotation readings.

Instead, I decided to make only one Mode, one that uses only the acceleration readings form the Y and Z axes. For this purpose, the acceleration readings were accurate enough, and I already had plenty of success using it.

The second problem was this. In both of the old modes and the new one, the joystick’s click function was going to turn Arduino’s output on and off. This would have let me choose when my motion was intended for performance and when to have the computer ignore it.

(Left) Joystick detects several clicks at a time (bouncing). (Right) Solution: apply a minimum delay that I measured with a stopwatch.

First, I the joystick was reading several button-downs and button-ups with one single click (called bouncing). My solution was for the Arduino, as soon as it read a button press, to wait 5 milliseconds before it read anything else. I measured the fastest I could possibly double-click button by using my watch’s stopwatch, and found that was around 8 milliseconds.

Successful debounce and communication with Max.

Once I successfully debounced the button, I also successfully made Max register the button-down as distinct from the button-up. I even got Max to freeze and unfreeze the joystick’s output based on if the button was pressed not.

Unfortunately, for some reason, putting the joystick and accelerometer together, I was only able to unfreeze the Arduino’s output with a click-down command, but never freeze it again with a click-up. I never knew why, and scrapped that feature, too.

Discussion

Students’ Critique

This was one student’s response to my project, in particular, to my presentation.

It would be good to get a background about the project before diving right into the demo because I wasn’t sure what we were looking at initially.

I couldn’t agree more with this. The demonstration was just Logic playing back a synthesize chord, and my motion changing the sound in bizarre and uninteresting ways. I do like giving the audience a sense of discovery, but since I didn’t verbally give context, and my performance didn’t fill that gap either, my cues didn’t help the audience grasp the device’s usefulness.

Later I was playing around with my device, improvising a performance, and realized how easy and compelling it would’ve been to do that performance for my presentation. Rip.

I absolutely love this:

Is there a way to preset chords such that as you rotate your wrist, it plays a simple song forwards or backwards?

What comes to my mind is called an arpeggiator. This is a really good idea, and possibly an easy one to implement. I could do it in Max and have it generate MIDI notes there. Logic also has MIDI plugin that lets you program in JavaScript any MIDI effect; maybe I could do it there.

This critique was my favorite.

Maybe have some sort of way to set it while inside the bathroom and display outside

Go ahead and let that simmer :=)

Lessons Learned.

My absolute greatest success in this project was making the simplest tests I could come up with. Even before I typed a single line of code, I chopped up the entire project into these tests, and scheduled out when I was going to make them, weeks in advance. This also included making schematics for each sub-circuit I had to test.

I ran tests as simple as printing the accelerometer axes on the Arduino. I made the Arduino, by itself, talk to Max with hard-coded numbers. I made Max, by itself, talk to Logic. Then I put all of those together and made the accelerometer talk to Max, and later, to Logic. And thus I scaffolded from very simple examples like that to the entire finished build.

This made it extremely easy to isolate the unique bugs of each subsystem and not let issues from other systems bleed over. Not only did I learn how to solve these issues, I mostly only had to solve them once! Because then I could take that success with me for the entire rest of the build!

I did find that each test was way less trivial than I thought at first. I would have way more problems than I expected, and the seemingly really long time cushions I would allocate for myself, I would spend all of it, or more, trying to solve those problems. It made me all the more grateful to have made “small” tests, and also to have scheduled such long cushions.

I will definitely keep these very good project management habits.

Next Steps

In the next iteration, I will definitely keep in mind that fantastic idea of arpeggiation. Maybe the angle of my wrist could correspond to playback speed, or I could build upon that idea in different ways.

I will also make a much sturdier, reusable, plug-and-play version setup. One that I don’t have to rip everything up every time I need the parts for something else. One that lets me just plug in the Arduino, the joystick, the accelerometer, and all of the cables.

Dissembling (actually destroying) the device

It would also be fantastic to have a drop-down menu in Max that lets me select what MIDI parameter I want each accelerometer and joystick axis to affect, and through what MIDI channel. Right now those things are hard-coded, and I need to unlock the patch and change the code to change the mapping.

Technical Information

Functional Block Diagrams and schematics for final build, as well as sub-systems

/* Gestural Midi Controller
 *
 * Carlos Ortega (carlosor)
 * 
 * Reads data from all axes of an accelerometer and a joystick,
 * converts the data into a usable range for MIDI,
 * formats the data to be interpretted in Max/MSP,
 * and sends to Max.
 * 
 * Pin Mapping:
 * 
 * Accel x      A0
 * Accel y      A1
 * Accel z      A2
 * 
 * Joy x        A3
 * Joy y        A4
 * 
 * Joy Switch   2
 * 
 */

typedef int pin_t;
// Accelerometer pin mappings
pin_t ACCEL_X_PIN = A0;
pin_t ACCEL_Y_PIN = A1;
pin_t ACCEL_Z_PIN = A2;

// Joystick pin mappings
pin_t JOY_X_PIN = A3;
pin_t JOY_Y_PIN = A4;
pin_t JOY_SW_PIN = 2;

// Axis indices
typedef byte axis_t;
axis_t AXIS_X = 0;
axis_t AXIS_Y = 1;
axis_t AXIS_Z = 2;

axis_t JOY_SW = 255;

// Device type
typedef String device_t;
device_t DEV_ACCEL = "accel";
device_t DEV_JOY = "joy";

typedef String clickstate_t;
clickstate_t CLK = "clk";
clickstate_t UNCLK = "unclk";
clickstate_t NO_CHANGE = "no_change";

// Used for checking the moment 
// when the joystick switch was clickedf
clickstate_t last_clck_state = UNCLK;
unsigned long clickTimer = 0;

// Returns pin number for device at axis
pin_t getAxisPin(axis_t axis, device_t device)
{
  pin_t pin = 0;
  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X) pin = ACCEL_X_PIN;
    else if (axis == AXIS_Y) pin = ACCEL_Y_PIN;
    else if (axis == AXIS_Z) pin = ACCEL_Z_PIN;
  }
  else if (device.equals(DEV_JOY))
  {
    if (axis == AXIS_X) pin = JOY_X_PIN;
    else if (axis == AXIS_Y) pin = JOY_Y_PIN;
    else if (axis == JOY_SW) pin = JOY_SW_PIN;
  }
  return pin;
}

int getData(axis_t axis, device_t device)
{
  pin_t pin = getAxisPin(axis, device);
  if (axis == JOY_SW) return digitalRead(pin);
  return analogRead(pin);
}

// Have 5 millis passed since last switch?
bool clickWaitOver()
{
  return millis() - clickTimer > 5;
}

void updateClickTimer()
{
  clickTimer = millis();
}

// Determine if button was just now clicked, unclicked, or no change.
clickstate_t getSetClickState()
{
  clickstate_t clickState = last_clck_state;
  if (clickWaitOver())
  {
    // clickTimer = 0; // Reset timer
    
    bool clickedThen = last_clck_state.equals(CLK);
    // Input pullup makes for inverted button pressed state
    bool clickedNow = getData(JOY_SW, DEV_JOY) == LOW;

    if (!clickedThen && clickedNow) clickState = CLK;
    else if (clickedThen && !clickedNow) clickState = UNCLK;
  }
  updateClickTimer();
  if (last_clck_state == clickState) return NO_CHANGE;

  last_clck_state = clickState;
  return clickState;
}

bool clicked()
{
  return (getSetClickState()).equals(CLK);
}

bool unclicked()
{
  return (getSetClickState()).equals(UNCLK);
}

// Read from given pin for given device, and convert to MIDI.
byte getMidi(axis_t axis, device_t device)
{
  int data = getData(axis, device);
  int MIDI_LO = 0;
  int MIDI_HI = 127;

  // For joystick, no change needed for the following initialized values.
  int dataLo = 0;
  int dataHi = 1023;

  byte midi = 255;

  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X)
    {
      dataLo = 278;
      dataHi = 413;
    }
    else if (axis == AXIS_Y)
    {
      dataLo = 260;
      dataHi = 408;
    }
    else if (axis == AXIS_Z)
    {
      dataLo = 270;
      dataHi = 412;
    }
  }
  // If checking Joystick only change midi if not checking switch.
  if (axis != JOY_SW) midi = map(data, dataLo, dataHi, MIDI_LO, MIDI_HI);
  return midi;
}

// Print MIDI data formatted to be read in Max.
void sendMidi(axis_t axis, device_t device)
{
  String prefix = "";
  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X) prefix = "X"; // Ascii 88
    else if (axis == AXIS_Y) prefix = "Y"; // Ascii 89
    else if (axis == AXIS_Z) prefix = "Z"; // Ascii 90
  }

  else if (device.equals(DEV_JOY))
  {
    if (axis == AXIS_X) prefix = "x"; // Ascii 120
    else if (axis == AXIS_Y) prefix = "y"; // Ascii 121
    else if (axis == JOY_SW)
    {
      if (clicked()) prefix = "+\n"; // Ascii 43
      else if (unclicked()) prefix = "-\n"; // ascii 45
    }
  }
  byte midi = getMidi(axis, device);
  Serial.print(prefix);
  // 255 reserved for click. Only print midi if not for click.
  if (midi < 255) Serial.println(midi);
}

// Run initilization for Accelerometer
void setupAccel()
{
  pinMode(getAxisPin(AXIS_X, DEV_ACCEL), INPUT);
  pinMode(getAxisPin(AXIS_Y, DEV_ACCEL), INPUT);
  pinMode(getAxisPin(AXIS_Z, DEV_ACCEL), INPUT);
}

// Run initilization for Joystick
void setupJoy()
{
  pinMode(getAxisPin(AXIS_X, DEV_JOY), INPUT);
  pinMode(getAxisPin(AXIS_Y, DEV_JOY), INPUT);
  pinMode(getAxisPin(JOY_SW, DEV_JOY), INPUT_PULLUP);
}

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

void loop()
{
  sendMidi(AXIS_X, DEV_ACCEL);
  sendMidi(AXIS_Y, DEV_ACCEL);
  sendMidi(AXIS_Z, DEV_ACCEL);

  sendMidi(AXIS_X, DEV_JOY);
  sendMidi(AXIS_Y, DEV_JOY);
  sendMidi(JOY_SW, DEV_JOY);
  delay(10);
}

Code in the Max patch and subpatches

]]>