Course Description

Art B2050, Fall 2013, DIAP at CCNY
A survey of modern electromechanical construction. Lessons interweave hardware, firmware, software and networking. Specific focus on paper and cardboard prototyping.

Wednesday, December 11, 2013

Week 14, 12/11: Music Box 2

All the files for our music box can be found here: http://lauralippincott.com/musicbox

Here's the Sketchup file I have for us to start from. It has a cutout for each component, and interlocking box joints that require no glue or nails. We'll need to build a linkage to lift the lid, and a dancer to spin on the continuous rotation servo. Basel has composed a melody for us using the Pitches library.



#include "pitches.h"

// notes in the melody:
int melody[] = { NOTE_D3, NOTE_F3, NOTE_A3, NOTE_G3, 
NOTE_C3, 0, NOTE_C3, NOTE_D3, NOTE_F3, 
NOTE_A3, NOTE_D3, NOTE_F3, NOTE_A3, 
NOTE_G3, NOTE_C3, 0, NOTE_C3, NOTE_F3, 
NOTE_F3, NOTE_A3 };

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = { 34, 20, 20, 25, 45, 20, 20, 30, 
40, 30, 55, 23, 56, 40, 35, 23, 67, 5 };

void setup(){
}

void loop(){
  for (int thisNote = 0; thisNote < 18; thisNote++) {
    int noteDuration = 1000/noteDurations[thisNote]; // one second divided by note duration
    tone(8, melody[thisNote], noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    noTone(8); // stop the melody
    delay(1000); // pause for a second
  }
}

Wednesday, December 4, 2013

Week 13, 12/4: Music Box

1. Piezo Sensor: Phyllis
We're still having trouble getting readings from the piezo sensor, but the idea is that an initial knock will activate the box. Deliverables: datasheet, circuit diagram, detectKnock() function that has a boolean knockDetected.

2. Standard Servo: William
William's job is to build the linkage that translates the motion of the servo to the door lifting up. Deliverables: datasheet, circuit diagram, openDoor() and closeDoor() functions, linkage.

3. Photoresistor: Shiang
When the door opens, light will hit the photoresistor and activate the RGB LED. The photoresistor has a boolean for lightDetected. When the box is closed, lightDetected is false. When the box is open, the brightness of the LED will be inversely proportional to the brightness of the room. Deliverables: datasheet, circuit diagram, detectLight() function, global boolean.

4. Continuous Rotation Servo: Michael
The motor will spin a dancer clockwise during the day and counterclockwise at night. When the global variable lightDetected is false, the motor won't move. Deliverables: datasheet, circuit diagram, spinDancer() function.

5. Gyroscope: Marianna
The values for the XYZ of the gyroscope will be mapped to the RGB of the LED. Deliverables: datasheet, circuit diagram, readGyro() function, gyroXYZ[] array.

6. Piezo Buzzer: Basel
Basel is composing a melody for the dancer. It should be responsive in some way to the motions of the dancer via gyroXYZ[]. Deliverables: datasheet, circuit diagram, playMelody() function, melody.

7. Ping Sensor: Robert
An always-on ping sensor will deactivate the box when the viewer walks away. Deliverables: datasheet, circuit diagram, readPing() function.

8. RGB LED: Clarinda
The RGB LED will be influenced by both the photoresistor and the gyroscope. The RGB values will be stored in an array, and mapped to the XYZ array of the gyroscope. Deliverables: datasheet, circuit diagram, changeColor() function, global ledRGB[] array.

The things we'll need to work on collectively are the master circuit diagram, the code architecture, and the box. I think we should 3D print the box. This is what I have so far in SketchUp; we can figure out how to add holes to mount all the components and Arduino in it. Inline image 1
I'm excited about this, hope you guys are too! We'll only end up with one, but with good design and documentation, everyone could easily make one of their own. 

Wednesday, November 20, 2013

Week 12, 11/20: Motor IO

It's your job to apply the code from the Light IO tutorial to a servo motor and potentiometer.

Code for a Standard Servo
#include <Servo.h> 
Servo SDservo;
int servoPin = 9;
int potPin = 0;
int potVal = 0;

void setup(){ 
  SDservo.attach(servoPin);


void loop(){ 
  controlServo();
  delay(15);


void controlServo(){
  potVal = analogRead(potpin);
  int mappedVal = map(potVal, 0, 1023, 0, 179);
  SDservo.write(mappedVal);
}

Code for a Continuous Rotation Servo
#include <Servo.h>

Servo CRservo;
const int halt = 90;

void setup(){
  CRservo.attach(7);
}

void loop(){
  CRservo.write(halt+20);
  delay(500);
  CRservo.write(halt-20);
  delay(500);
  CRservo.write(halt);
  delay(2000);
}

Code for Four Standard Servos
#include <Servo.h> 

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

int pos = 0;

void setup(){ 
  Serial.begin(9600);
  servo1.attach(3);
  servo2.attach(4);
  servo3.attach(5);
  servo4.attach(6);

void loop() { 
  sweep(servo1, 1, 80, 120, 30);
  sweep(servo2, 1, 80, 160, 15);
  sweep(servo3, 1, 100, 160, 15); 
  sweep(servo4, 1, 60, 140, 15);

void sweep(Servo s, int inc, int smin, int smax, int del){
  for(int pos=smin; pos < smax; pos += inc){
    s.write(pos);
    delay(del);
  }
}

Thursday, November 14, 2013

Week 11, 11/13: Light IO



Code Version 1

int LEDpin = 9;
int PRpin = A0;
int PRval, LEDval;

void setup(){
  pinMode(LEDpin, OUTPUT);
  pinMode(PRpin, INPUT);
  Serial.begin(9600);
}

void loop(){
  readPR();
  writeLED();
}

void readPR(){
  PRval = analogRead(PRpin);
  Serial.print("PRval = ");
  Serial.print(PRval);
}

void writeLED(){
  LEDval = map(PRval, 0, 450, 0, 255);
  analogWrite(LEDpin, LEDval);
  Serial.print(", LEDval = ");
  Serial.println(LEDval); 
}

Code Version 2

int LEDpin = 9;
int PRpin = A0;
int PRval, LEDval, num;

void setup(){
  pinMode(LEDpin, OUTPUT);
  pinMode(PRpin, INPUT);
  Serial.begin(9600);
}

void loop(){
  readPR();
  Serial.print("PRval = ");
  Serial.print(PRval);
  if(PRval < 10) num = 1;
  else if(PRval > 300) num = 3;
  else num = 2;
  switch(num){
    case 1: // PR is in shadow
      Serial.println("shadow");
      digitalWrite(LEDpin, LOW);
      break;
    case 2: // PR is in ambient light
      Serial.println("ambient");
      writeLED();
      break;
    case 3: // PR is in bright light
      Serial.println("bright");
      digitalWrite(LEDpin, LOW);
      break;
  }
  delay(20);
}

void readPR(){
  PRval = analogRead(PRpin);
}

void writeLED(){
  LEDval = map(PRval, 0, 450, 255, 0);
  analogWrite(LEDpin, LEDval);
}

Wednesday, November 6, 2013

Week 10, 11/6: Debugging

So far we've seen all the ways a physical computing project can be difficult. Here's a troubleshooting checklist to help you figure out what's going wrong.

1. Is the code correct?
Code is the most complex and most edited part of a project, so it's the most likely source of a bug. This is why it's so important to keep your code clean and well-organized. Give each component its own function, keep variables local, and give the functions and variables obvious names. Use Serial.print() and Serial.println() liberally (then comment them out when you're done).

2. Did it work before you changed something?
If yes, isolate the change. Comment things out until you've located the problem. Save working versions of the code with clear version numbers (and don't save non-working versions). It may be that the newest change revealed an older bug, but that's less likely. If the code has never worked, and you're sure the code is right, check the wiring.

3. Is the wiring correct?
Visually inspect all soldered and solderless connections. Use the multimeter on the continuity setting to ensure conduction is happening where it's needed, and not happening elsewhere. Use the multimeter on the DC voltage setting to make sure the right amount of power is getting to each component. Isolate each component to make sure they're not interfering with each other.

Wednesday, October 30, 2013

Week 9, 10/30: Sensors

Sensors come in many shapes and sizes. Understanding what types of sensors are around at what price points will help you shape your projects. The thing most of you were interested in sensing was the presence and proximity of people, so here are two sensors for that purpose. A piezo sensor detects vibration— a very crude version of a microphone. A ping sensor emits and detects an ultrasonic pulse; the time it takes the pulse to return to the sensor tells you how far away the closest object is. 

Sensors typically have two or three terminals. Every sensors needs power, ground, and at least one signal wire. With two-terminal sensors, like photoresistors and piezos, a voltage divider is required. The ground terminal connects to ground; the positive terminal connects to the signal input pin and also to a resistor; the resistor connects to the source voltage.



Piezo Code
int ledPin = 13;
int knockSensor = 0; 
byte val = 0;
int statePin = LOW;
int THRESHOLD = 100;

void setup(){
  pinMode(ledPin, OUTPUT); 
  Serial.begin(9600);
}

void loop(){
  val = analogRead(knockSensor); 
  if (val >= THRESHOLD) {
    statePin = !statePin;
    digitalWrite(ledPin, statePin);
    Serial.println("Knock!");
  }
  delay(100);
}

Ping Code
const int pingPin = 10;

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

void loop(){
  Serial.println(ping());
  delay(100);
}

int ping(){
  long duration, cm;
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  return cm;
}

long microsecondsToCentimeters(long microseconds){
  return microseconds / 29 / 2;
}


Wednesday, October 16, 2013

Week 8, 10/23: Processing

Today we'll look at the art history of mechanical systems. Here's a link to the image gallery, here's a link to the reading, here's a link to the circuit symbol index. We'll also talk about how the four programming paradigms— imperative, functional, object-oriented, logic— and how they're all encapsulated in the familiar line, Serial.println("hello world");

The goal of today's workshop is to get Arduino communicating with Processing. It's easier to go from Processing to Arduino than the reverse, so we'll start there. The one trick to getting this working is to select the correct Serial port in Processing. When you first launch the Processing code, it will list the Serial ports in the debugging window. One will match the board ID# you selected in the Arduino/Tools menu. Whatever number in the list matches your board ID# will be substituted for 0 in the line port = new Serial(this, Serial.list()[0], 9600);


Arduino Code
const int ledPin = 13; 
int incomingByte;

void setup(){
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if(Serial.available() > 0){
    incomingByte = Serial.read();
    if(incomingByte == 'H'){
      digitalWrite(ledPin, HIGH);
    } 
    if(incomingByte == 'L'){
      digitalWrite(ledPin, LOW);
    }
  }
}

Processing Code
import processing.serial.*; 
float boxX;
float boxY;
int boxSize = 20;
boolean mouseOverBox = false;
Serial port; 

void setup(){
  size(200, 200);
  boxX = width/2.0;
  boxY = height/2.0;
  rectMode(RADIUS); 
  println(Serial.list());  // find your Arduino in log list
  port = new Serial(this, Serial.list()[0], 9600);
}

void draw(){ 
  background(0);
  if (mouseX > boxX-boxSize && mouseX < boxX+boxSize && 
    mouseY > boxY-boxSize && mouseY < boxY+boxSize) {
    mouseOverBox = true;  
    stroke(255); 
    fill(153);
    port.write('H');
  } 
  else {
    stroke(153);
    fill(153);
    port.write('L');      
    mouseOverBox = false;
  }

  rect(boxX, boxY, boxSize, boxSize);
}