Thank god this week is over. It was looking a little sketchy for a while, but it all came together in the end, everyone had fun and nobody got hurt.
The week started off with investigating sound generation. We divided the team into 2 groups: two of us looked into MIDI, and the other two researched getting sound out of processing via SONIA.
I worked on the MIDI side of things and found the code quite easy (copied right out of the Physical Computing book.) Hooking up the breadboard to a MIDI synth was also a breeze, and getting different sounds out of it was pleasing. It does have its limitations though as we were just getting one note at a time, be it from a trumpet or a harpsichord. It lacked the entertainment value and pizzazz that we were hoping to achieve with our project, however we did have it up and running rather quickly.
Sadly, the problem with the sensors persisted. We continued to struggle with inconsistent signals from the paddle, making it hard to develop a reliable system. If we set our threshold to a high number, it would take a mighty smack on the paddle to produce a sound out of the MIDI. If we set the threshold low, the slightest vibration would cause a steady stream of numbers to flow from the sensor in the paddle. And then to make matters worse, occasionally the sensor would just stop sending numbers altogether. Combine all of this with other midterms and the usual time pressures, and you have a team that is close to implosion.
In a last ditch effort, we turned to past experience and Steven tracked down a second year student who had done a similar project last term. After picking his brain, Steven replicated his paddle design with some PIEZO buzzers from RadioShack and Gorilla glue. This was the winning combination that produced a reliable paddle. We also used a program from Tom Igoe that helped set up a variable threshold that worked better than the one we had cobbled together ourselves. The team also worked on the processing/SONIA so I’ll let them explain how that coalesced (I was in class at the time.) Their work did allow us to use our own recorded sounds, much to everyone’s delight. -TA
I’m going to post the code here in case no one else does:
' Define ADCIN parameters
DEFINE ADC_BITS 10 ' Set number of bits in result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 20 ' Set sampling time in uS
PeakValue var word
SensorValue var word
LastSensorValue var word
Threshold var word
Noise var word
PingPong VAR WORD
PingPong = 420
' serial pins and data reate:
tx var portc.6
rx var portc.7
n9600 con 16468
Threshold = 50 ' set your own value based on your sensors
PeakValue = 0 ' initialize peakValue
noise = 5 ' set a noise value based on your particular sensor
' Set PORTA to all input
TRISA = %11111111
' Set up ADCON1
ADCON1 = %10000010
Main:
' read sensor on pin RA0:
ADCin 3, sensorValue
' check to see that it's above the threshold:
If sensorValue >= threshold + noise then
' if it's greater than the last reading,
' then make it our current peak:
If sensorValue >= lastSensorValue + Noise then
PeakValue = sensorValue
endif
' if the sensorValue is not above the threshold,
' then the last peak value we got would be the actual peak:
Else
If peakValue >= threshold then
' this is the final peak value; take action
'serout2 tx, n9600, ["peak reading", DEC peakValue, 13,10]
'serout2 tx, n9600, [DEC peakValue]
serout2 tx, n9600, [DEC pingPong]
endif
' reset peakValue, since we've finished with this peak:
peakValue = 0
Endif
' store the current sensor value for the next loop:
lastSensorValue = sensorValue
Goto main
Processing:
import pitaru.sonia_v2_9.*;
import processing.serial.*;
int bgcolor; // background color
int fgcolor; // fill color
Serial port; // the serial port
int[] serialInArray = new int[3]; // where we'll put what we receive
int serialPong = 0;
int serialCount = 0; // a count of how many bytes we receive
float xpos, ypos; // Starting position of the ball
boolean firstContact = false; // whether we've heard from the microcontroller
Sample bounce;
void setup() {
size(256, 256); // stage size
noStroke(); // no border on the next thing drawn
// Set the starting position of the ball (middle of the stage)
xpos = width/2;
ypos = height/2;
// print a list of the serial ports, for debugging purposes:
println(Serial.list());
/* I know that the first port in the serial list on my mac
is always my Keyspan adaptor, so I open Serial.list()[0].
On Windows machines, this generally opens COM1.
Open whatever port is the one you're using.
*/
port = new Serial(this, Serial.list()[0], 9600);
//port.write(65); // send a capital A to start the microcontroller sending
Sonia.start(this); // Start Sonia engine.
// create a new sample object.
bounce = new Sample("pingpong.wav");
}
void draw() {
background(bgcolor);
fill(fgcolor);
// Draw the shape
ellipse(xpos, ypos, 20, 20);
// get any new serial data:
while (port.available() > 0) {
serialEvent();
// note that we heard from the microntroller:
firstContact = true;
}
// if there's no serial data,
// send again until we get some.
// (in case you tend to start Processing
// before you start your external device):
//if (firstContact == false) {
// delay(300);
// port.write(65);
//}
}
void serialEvent() {
processByte((char)port.read());
}
void processByte(char inByte) {
// add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
// if we have 3 bytes:
if (serialCount > 2 ) {
//xpos = (float)serialInArray[0];
//ypos = (float)serialInArray[1];
//fgcolor = (int)serialInArray[2];
serialPong = (int)serialInArray[0];
println(serialPong);
if (serialPong == 52) {
bounce.play();
}
// send a capital A to request new sensor readings:
//port.write(65);
// reset serialCount:
serialCount = 0;
}
}
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}