Created
July 2, 2011 22:25
-
-
Save mshuster/1061729 to your computer and use it in GitHub Desktop.
Synthdriver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Wire.h> | |
#define PI 3.14159265358979323846 | |
#define ACCEL (0x53) //ADXL345 device address | |
#define TO_READ (6) //num of bytes we are going to read each time (two bytes for each axis) | |
#define g0 9.812865328 | |
#define ACCELEROMETER_GAIN (0.004 * g0) | |
//MIDI Presets | |
#define CC = 176 | |
#define DEFAULT_CHANNEL = 12 | |
//Accelerometer | |
#define R_INT_ENABLE = 46 | |
#define R_INT_MAP = 47 | |
#define R_THRESH_TAP = 29 | |
#define R_DUR = 33 | |
#define R_TAP_AXES 42 | |
// Gyroscope ITG3200 | |
#define GYRO (0x68) // gyro address, binary = 11101001 when AD0 is connected to Vcc (see schematics of your breakout board) | |
#define G_SMPLRT_DIV 0x15 | |
#define G_DLPF_FS 0x16 | |
#define G_INT_CFG 0x17 | |
#define G_PWR_MGM 0x3E | |
#define G_TO_READ 8 // 2 bytes for each axis x, y, z | |
#define G_X_OFFSET 14 | |
#define G_Y_OFFSET 47 | |
#define G_Z_OFFSET 10 | |
char str[512]; //string buffer to transform data before sending it to the serial port | |
int CALIBRATION_SAMPLES = 128; | |
int reads = 0; | |
int x, y, z; | |
volatile double a_x, a_y, a_z; | |
double a_xBias, a_yBias, a_zBias; | |
volatile double a_x_stack = 0; | |
volatile double a_y_stack = 0; | |
volatile double a_z_stack = 0; | |
volatile double g_x, g_y, g_z; | |
volatile double turn; | |
volatile double prev_turn = 64; | |
volatile double prev_a_z = 0; | |
volatile int last_pitch = 0; | |
volatile int last_roll = 0; | |
volatile int last_rotation = 0; | |
boolean noteon = false; | |
int last_note = 36; | |
int BASE_NOTE = 36; | |
int TRIGGER_CHANNEL = 13; | |
int SHAKE_TOLERANCE = 0; | |
int notes[7] = {0,2,4,5,7,9,11}; //1-octave scale | |
int last_pan = 0; | |
boolean toggle = false; | |
void setup() | |
{ | |
Wire.begin(); // join i2c bus (address optional for master) | |
Serial.begin(115200); // start serial for output | |
initAccel(); | |
initGyro(); | |
delay(22); | |
} | |
void loop() | |
{ | |
getAccelGyro(); | |
/* Flat chip orientation | |
double roll = atan2(a_y, sqrt( a_x * a_x + a_z * a_z)); | |
double pitch = atan2(a_x, sqrt( a_y * a_y + a_z * a_z)); | |
*/ | |
//Wheel orientation - Calculate the angle in RADs to the ground | |
double pitch = atan2(a_z, sqrt( a_y * a_y + a_x * a_x)); | |
double roll = atan2(a_y, sqrt( a_z * a_z + a_x * a_x)); | |
//Map the resulting values to a 7bit range | |
int pitch_range = (int)map(constrain(pitch * 180/PI, -90, 90), -90, 90, 0, 127); | |
int roll_range = (int)map(constrain(roll * 180/PI, -90, 90), -90, 90, 0, 127); | |
int leftPot = map(constrain(analogRead(3), 490, 1023),490,1023,0,6); | |
int rightPot = map(constrain(analogRead(2), 515, 1017), 515,1017,0,127); | |
//Lock the gyro turn to 90degrees in each direction | |
turn = constrain(turn,-90,90); | |
//Map the turn value to 7bit range | |
int rotation_range = map((int)constrain(turn,-90,90),-90,90,0,127); | |
//Add the selected note to middle C | |
int this_note = BASE_NOTE + notes[leftPot]; | |
//If there is contact on the leftPot engage the note | |
if ((analogRead(3) > 0)) { | |
if ((this_note != last_note) || (this_note == last_note && !noteon)) { | |
sendMIDI(144, last_note, 0); | |
sendMIDI(144, this_note, 127); | |
} | |
noteon = true; | |
last_note = this_note; | |
} //Turn notes off if there is no contact | |
else if ((analogRead(3) == 0) && noteon) { | |
sendMIDI(144, last_note, 0); | |
noteon=false; | |
} | |
/* Some gesture detection | |
if ((prev_a_z < -10.0) && (a_z > 0.0)) { | |
sendMIDI(144, last_note, 0); | |
noteon = false; | |
} | |
prev_a_z = a_z; | |
*/ | |
//When the change in values per cycle is greater than 0 (in this case) send the new midi command | |
if (abs(pitch_range - last_pitch) > SHAKE_TOLERANCE){ | |
sendMIDI(176, 10, pitch_range); | |
} | |
if (abs(roll_range - last_roll) > SHAKE_TOLERANCE){ | |
sendMIDI(176, 11, roll_range); | |
} | |
if (abs(rotation_range - last_rotation) > SHAKE_TOLERANCE) { | |
sendMIDI(176, 12, rotation_range); | |
} | |
if (leftPot != 0) { | |
//sendMIDI(176, 13, leftPot); | |
} | |
//Control the pan with right pot | |
if (rightPot != last_pan && rightPot != 0) { | |
sendMIDI(176, 13, rightPot); | |
last_pan = rightPot; | |
} //Return to middle if no contact | |
else if (rightPot != last_pan && rightPot == 0) { | |
sendMIDI(176, 13, 64); | |
last_pan = rightPot; | |
} | |
last_pitch = pitch_range; | |
last_roll = roll_range; | |
last_rotation = rotation_range; | |
} | |
void initAccel(){ | |
//Turning on the ADXL345 | |
writeTo(ACCEL, 0x2D, 0); | |
writeTo(ACCEL, 0x2D, 16); | |
writeTo(ACCEL, 0x2C, 0x0C); // Set BW 200hz | |
writeTo(ACCEL, 0x31, 0x0B); // Set BW 200hz | |
//TODO:TAP DETECTION | |
/* | |
writeTo(ACCEL, R_INT_MAP, 0); // send all interrupts to ADXL345's INT1 pin | |
writeTo(ACCEL, R_DUR, 0x1F); // 625us/LSB | |
writeTo(ACCEL, R_THRESH_TAP, 48); // 62.5mg/LSB <==> 3000mg/62.5mg = 48 LSB as datasheet suggestion | |
writeTo(ACCEL, R_TAP_AXES, 6); // enable tap detection on x,y,z axes | |
writeTo(ACCEL, R_INT_ENABLE, 96); // enable signle and double tap, activity, inactivity and free fall detection | |
*/ | |
writeTo(ACCEL, 0x2D, 8); //set power mode | |
} | |
void initGyro() | |
{ | |
/***************************************** | |
* ITG 3200 | |
* power management set to: | |
* clock select = internal oscillator | |
* no reset, no sleep mode | |
* no standby mode | |
* sample rate to = 125Hz | |
* parameter to +/- 2000 degrees/sec | |
* low pass filter = 5Hz | |
* no interrupt | |
******************************************/ | |
writeTo(GYRO, G_PWR_MGM, 0x00); | |
writeTo(GYRO, G_SMPLRT_DIV, 0x07); // EB, 50, 80, 7F, DE, 23, 20, FF | |
writeTo(GYRO, G_DLPF_FS, 0x1E); // +/- 2000 dgrs/sec, 1KHz, 1E, 19 | |
writeTo(GYRO, G_INT_CFG, 0x00); | |
} | |
//Read the accelerometer and gyro values to buffer | |
void getAccelGyro(){ | |
int gyroRegAddress = 0x1B; | |
byte gyroBuff[G_TO_READ]; | |
int accelRegAddress = 0x32; | |
byte accelBuff[TO_READ] ; | |
int samples = 10; | |
double LSB = 14.375; | |
int sample_rate = 125; | |
//Smoothing loop for accel, and sampling loop for gyro | |
for(int i = 0; i < 10; i++){ | |
readFrom(ACCEL, accelRegAddress, TO_READ, accelBuff); //read the acceleration data from the ADXL345 | |
//each axis reading comes in 10 bit resolution, ie 2 bytes. Least Significat Byte first!! | |
//thus we are converting both bytes in to one int | |
a_x_stack += (((int)accelBuff[1]) << 8) | accelBuff[0]; | |
a_y_stack += (((int)accelBuff[3])<< 8) | accelBuff[2]; | |
a_z_stack += (((int)accelBuff[5]) << 8) | accelBuff[4]; | |
readFrom(GYRO, gyroRegAddress, G_TO_READ, gyroBuff); //read the gyro data from the ITG3200 | |
g_x = ((int)(gyroBuff[2] << 8) | gyroBuff[3]) - G_X_OFFSET; | |
g_y = ((int)(gyroBuff[4] << 8) | gyroBuff[5]) - G_Y_OFFSET; | |
g_z = ((int)(gyroBuff[6] << 8) | gyroBuff[7]) - G_Z_OFFSET; | |
turn += g_x / LSB / sample_rate; //Integrate the turn value assuming 1 sample every 8ms | |
delay(5); //stretch the sampling interval so that we're at about 8ms | |
} | |
//Calculate the smoothed acceleration data into m/s/s | |
a_x = ((a_x_stack / samples) - a_xBias) * ACCELEROMETER_GAIN; | |
a_y = ((a_y_stack / samples) - a_yBias) * ACCELEROMETER_GAIN; | |
a_z = ((a_z_stack / samples) - a_zBias) * ACCELEROMETER_GAIN; | |
a_x_stack = 0; | |
a_y_stack = 0; | |
a_z_stack = 0; | |
} | |
//Method to calibrate accelerometer offset | |
void calibrateAccelerometer(void) { | |
int regAddress = 0x32; | |
byte buff[TO_READ] ; //6 bytes buffer for saving data read from the device | |
a_x_stack = 0; | |
a_y_stack = 0; | |
a_z_stack = 0; | |
//Take a number of readings and average them | |
//to calculate the zero g offset. | |
for (int i = 0; i < CALIBRATION_SAMPLES; i++) { | |
readFrom(ACCEL, regAddress, TO_READ, buff); //read the acceleration data from the ADXL345 | |
//each axis reading comes in 10 bit resolution, ie 2 bytes. Least Significat Byte first!! | |
//thus we are converting both bytes in to one int | |
a_x_stack += (((int)buff[1]) << 8) | buff[0]; | |
a_y_stack += (((int)buff[3])<< 8) | buff[2]; | |
a_z_stack += (((int)buff[5]) << 8) | buff[4]; | |
delay(5); | |
} | |
a_x_stack /= CALIBRATION_SAMPLES; | |
a_y_stack /= CALIBRATION_SAMPLES; | |
a_z_stack /= CALIBRATION_SAMPLES; | |
//At 4mg/LSB, 250 LSBs is 1g. | |
a_xBias = (a_x_stack - 250); | |
a_yBias = a_y_stack; | |
a_zBias = a_z_stack; | |
a_x_stack = 0; | |
a_y_stack = 0; | |
a_z_stack = 0; | |
} | |
//Writes val to address register on device | |
void writeTo(int device, byte address, byte val) { | |
Wire.beginTransmission(device); //start transmission to device | |
Wire.send(address); // send register address | |
Wire.send(val); // send value to write | |
Wire.endTransmission(); //end transmission | |
} | |
//reads num bytes starting from address register on device in to buff array | |
void readFrom(int device, byte address, int num, byte buff[]) { | |
Wire.beginTransmission(device); //start transmission to device | |
Wire.send(address); //sends address to read from | |
Wire.endTransmission(); //end transmission | |
Wire.beginTransmission(device); //start transmission to device | |
Wire.requestFrom(device, num); // request 6 bytes from device | |
int i = 0; | |
while(Wire.available()) //device may send less than requested (abnormal) | |
{ | |
buff[i] = Wire.receive(); // receive a byte | |
i++; | |
} | |
Wire.endTransmission(); //end transmission | |
} | |
void sendMIDI(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command | |
{ | |
Serial.print(MESSAGE); | |
Serial.print(CONTROL); | |
Serial.print(VALUE); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment