Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FSR LSM9DS1_Library_cal USBMIDI mbed
Fork of LSM9DS1_Demo_wCal by
main.cpp
00001 #include "mbed.h" 00002 #include "USBMIDI.h" 00003 #include "LSM9DS1.h" 00004 #include "math.h" 00005 #include "FSR.h" 00006 00007 #define PI 3.14159 00008 #define BUFFERSIZE 6 00009 00010 // FSR 00011 FSR fsr_kick(p20, 10); // Pin 20 is used as the AnalogIn pin and a 10k resistor is used as a voltage divider 00012 FSR fsr_hh(p19, 10); // Pin 19 is used as the AnalogIn pin and a 10k resistor is used as a voltage divider 00013 bool hh_close = false; // boolean to determine if hi-hat is closed or open 00014 bool kicked = false; 00015 00016 // IMU 00017 LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); 00018 LSM9DS1 IMU2(p28, p27, 0xD6, 0x3C); 00019 00020 USBMIDI midi; 00021 00022 Serial pc(USBTX, USBRX); 00023 DigitalOut led1(LED1); 00024 DigitalOut led2(LED2); 00025 DigitalOut led3(LED3); 00026 DigitalOut led4(LED4); 00027 00028 Timer t; 00029 float t_prev = 0; 00030 float t_prev2 = 0; 00031 float t_curr = 0; 00032 float t_curr2 = 0; 00033 float t_gyroPrev = 0; 00034 float t_gyroPrev2 = 0; 00035 float t_gyroCurr = 0; 00036 float t_gyroCurr2 = 0; 00037 float delta_t = 0; 00038 00039 float y_accel = 0; 00040 float y_accel2 = 0; 00041 00042 int resetIndex = BUFFERSIZE - 2; 00043 float average[BUFFERSIZE] = {0}; 00044 int avg_index = 0; 00045 float total = 0; 00046 float avg_thresh = 20; 00047 00048 float average2[BUFFERSIZE] = {0}; 00049 int avg_index2 = 0; 00050 float total2 = 0; 00051 float avg_thresh2; 00052 00053 float prev_y_accel = 0; 00054 float curr_y_accel = 0; 00055 float y_accel_threshold = 0.8; 00056 bool check_y_accel = false; 00057 float t_prev_y_accel = 0; 00058 00059 float prev_y_accel2 = 0; 00060 float curr_y_accel2 = 0; 00061 bool check_y_accel2 = false; 00062 float t_prev_y_accel2 = 0; 00063 00064 int count2 = 0; 00065 int count = 0; 00066 00067 bool detectHit = 0; 00068 bool detectHit2 = 0; 00069 bool detectUp = 0; 00070 bool detectUp2 = 0; 00071 00072 float runningAvg = 0; 00073 float runningAvg2 = 0; 00074 00075 float interval = 0.20; 00076 float hit_volume = 0; 00077 float hit_volume2 = 0; 00078 00079 enum StateType {FRONT, SIDE, HIT}; 00080 enum StateType2 {FRONT2, SIDE2, HIT2}; 00081 00082 StateType state = FRONT; // Initial state is FRONT 00083 StateType2 state2 = FRONT2; 00084 00085 void show_message(MIDIMessage msg) { 00086 switch (msg.type()) { 00087 case MIDIMessage::NoteOnType: 00088 printf("NoteOn key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel()); 00089 break; 00090 case MIDIMessage::NoteOffType: 00091 printf("NoteOff key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel()); 00092 break; 00093 case MIDIMessage::ControlChangeType: 00094 printf("ControlChange controller: %d, data: %d\n", msg.controller(), msg.value()); 00095 break; 00096 case MIDIMessage::PitchWheelType: 00097 printf("PitchWheel channel: %d, pitch: %d\n", msg.channel(), msg.pitch()); 00098 break; 00099 default: 00100 printf("Another message\n"); 00101 } 00102 } 00103 00104 00105 int main() 00106 { 00107 midi.attach(show_message); // call back for messages received 00108 pc.baud(9600); 00109 pc.printf("Hello world!\n"); 00110 00111 // Initialize IMUs 00112 IMU.begin(); 00113 if (!IMU.begin()) { 00114 pc.printf("Failed to communicate with LSM9DS1 - first.\n"); 00115 } 00116 IMU.calibrate(1); 00117 00118 IMU2.begin(); 00119 if (!IMU2.begin()) { 00120 pc.printf("Failed to communicate with LSM9DS1 - second.\n"); 00121 } 00122 IMU2.calibrate(1); 00123 00124 t.start(); // start timer 00125 00126 while(1) { 00127 00128 // Initialize acceleration and gyroscope data for both IMUs 00129 while(!IMU.accelAvailable()); 00130 IMU.readAccel(); 00131 while(!IMU.gyroAvailable()); 00132 IMU.readGyro(); 00133 00134 while(!IMU2.accelAvailable()); 00135 IMU2.readAccel(); 00136 while(!IMU2.gyroAvailable()); 00137 IMU2.readGyro(); 00138 00139 // Create variables for ease of use for acceleration 00140 y_accel = IMU.calcAccel(IMU.ay); 00141 y_accel2 = IMU2.calcAccel(IMU2.ay); 00142 00143 // Initialize timer 00144 t_curr = t.read(); 00145 t_curr2 = t_curr; 00146 00147 00148 /** 00149 * FSR detection 00150 */ 00151 00152 // Check if values from FSRs are above a threshold (to detect hit) 00153 if (fsr_kick.readRaw() > 0.3){ 00154 // Sound will only play if foot is not on FSR (eliminates continuous noise playing if pedal is held down) 00155 if (kicked == false){ 00156 midi.write(MIDIMessage::NoteOn(45, fsr_kick.readRaw() * 127 + 30, 10)); // Play a kick, map the volume and boost the amplitude, channel 10 00157 } 00158 kicked = true; 00159 } 00160 else {kicked = false;} 00161 00162 if (fsr_hh.readRaw() > 0.3){ 00163 if (hh_close == false){ 00164 midi.write(MIDIMessage::NoteOn(42, fsr_hh.readRaw()*127, 10)); // Play a hi-hat pedal, map the volume, channel 10 00165 } 00166 hh_close = true; 00167 } 00168 else {hh_close = false;} 00169 00170 00171 /** 00172 * Running average for hit detection 00173 */ 00174 00175 // First IMU 00176 total -= average[avg_index]; 00177 average[avg_index] = IMU.calcGyro(IMU.gy); 00178 total += average[avg_index]; 00179 if (avg_index > resetIndex) { 00180 avg_index = 0; 00181 } else { 00182 avg_index++; 00183 } 00184 00185 // Second IMU 00186 total2 -= average2[avg_index2]; 00187 average2[avg_index2] = IMU2.calcGyro(IMU2.gy); 00188 total2 += average2[avg_index2]; 00189 if (avg_index2 > resetIndex) { 00190 avg_index2 = 0; 00191 } else { 00192 avg_index2++; 00193 } 00194 00195 /** 00196 * Hit detection 00197 */ 00198 00199 // Detect downward hit 00200 if (IMU.calcGyro(IMU.gy) > 35) { 00201 detectHit = 1; 00202 } 00203 00204 if (IMU2.calcGyro(IMU2.gy) > 35) { 00205 detectHit2 = 1; 00206 } 00207 00208 // Map gyroscope value ranges to volume ranges 00209 hit_volume = (runningAvg + 245) * (127) / (490); 00210 hit_volume2 = (runningAvg2 + 245) * (127) / (490) + 15; 00211 00212 // First IMU 00213 detectUp = IMU.calcGyro(IMU.gy) <= 0; 00214 runningAvg = total / BUFFERSIZE; 00215 00216 // Check if drumstick is brought down and then brought back up (eliminates continous hit detection if drumstick is just held tilted down) 00217 // Then check if running average is greater than a threshold (to elimate noise) 00218 // Elimate debouncing by only allowing a hit to play if the time interval has passed 00219 if (detectHit && detectUp && (runningAvg > avg_thresh) && (t_curr - t_prev) > interval) { 00220 // Depending on the state, play the corresponding instrument 00221 switch (state) { 00222 case (FRONT): 00223 midi.write(MIDIMessage::NoteOn(46, hit_volume, 10)); // Play ride sound 00224 break; 00225 case (SIDE): 00226 if (hh_close) { 00227 midi.write(MIDIMessage::NoteOn(40, hit_volume, 10)); // Play closed hi-hat sound 00228 } else { 00229 midi.write(MIDIMessage::NoteOn(41, hit_volume, 10)); // Play open hi-hat sound 00230 } 00231 break; 00232 } 00233 detectHit = 0; 00234 t_prev = t_curr; 00235 count = 0; 00236 } 00237 00238 // Second IMU 00239 detectUp2 = IMU2.calcGyro(IMU2.gy) <= 0; 00240 runningAvg2 = total2 / BUFFERSIZE; 00241 00242 if (detectHit2 && detectUp2 && runningAvg2 > avg_thresh2 && (t_curr2 - t_prev2) > interval) { 00243 switch (state2) { 00244 case (FRONT2): 00245 midi.write(MIDIMessage::NoteOn(47, hit_volume2, 10)); // Play snare sound 00246 break; 00247 case (SIDE2): 00248 midi.write(MIDIMessage::NoteOn(51, hit_volume2, 10)); // Play clap sound 00249 break; 00250 } 00251 detectHit2 = 0; 00252 t_prev2 = t_curr2; 00253 } 00254 00255 00256 /** 00257 * Instrument switching detection 00258 */ 00259 00260 curr_y_accel = y_accel; 00261 curr_y_accel2 = y_accel2; 00262 00263 check_y_accel = abs(curr_y_accel - prev_y_accel) > y_accel_threshold; 00264 check_y_accel2 = abs(curr_y_accel2 - prev_y_accel2) > y_accel_threshold; 00265 00266 // Check that y accleration is above threshold; if it is, increase the count for the number of cycles it is above this threshold 00267 if (check_y_accel) { 00268 count++; 00269 } 00270 00271 if (check_y_accel2) { 00272 count2++; 00273 } 00274 00275 // First IMU 00276 switch (state) { 00277 case (FRONT): 00278 // Check that y_accleration is above the threshold for at least 3 cycles 00279 // Elimnate debouncing by only switching if a time interval has passed 00280 if (check_y_accel && (count >= 3) && (t_curr - t_prev_y_accel) > 0.3) { 00281 count = 0; 00282 state = SIDE; 00283 led1 = 1; 00284 led2 = 0; 00285 t_prev_y_accel = t_curr; 00286 } 00287 break; 00288 case (SIDE): 00289 if (check_y_accel && (count >= 3) && (t_curr - t_prev_y_accel) > 0.3) { 00290 count = 0; 00291 state = FRONT; 00292 led1 = 0; 00293 led2 = 1; 00294 t_prev_y_accel = t_curr; 00295 } 00296 break; 00297 } 00298 prev_y_accel = curr_y_accel; 00299 00300 //Second IMU 00301 switch (state2) { 00302 case (FRONT2): 00303 if (check_y_accel2 && (count2 >= 3) && (t_curr - t_prev_y_accel2) > 0.3){ 00304 state2 = SIDE2; 00305 count2 = 0; 00306 led4 = 1; 00307 led3 = 0; 00308 t_prev_y_accel2 = t_curr; 00309 } 00310 break; 00311 case (SIDE2): 00312 if (check_y_accel2 && (count2 >= 3) && (t_curr - t_prev_y_accel2) > 0.3){ 00313 state2 = FRONT2; 00314 count2 = 0; 00315 led4 = 0; 00316 led3 = 1; 00317 t_prev_y_accel2 = t_curr; 00318 } 00319 break; 00320 } 00321 prev_y_accel2 = curr_y_accel2; 00322 } 00323 }
Generated on Wed Jul 13 2022 23:40:57 by
1.7.2
