Skip to content

Instantly share code, notes, and snippets.

@mshuster
Created July 2, 2011 22:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mshuster/1061729 to your computer and use it in GitHub Desktop.
Save mshuster/1061729 to your computer and use it in GitHub Desktop.
Synthdriver
#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