nibo
07.11.2011, 09:48
Hallo,
habe eine Melodie von J. S. Bach für den NIBObee umgesetzt. Die Melodie wird von den Motoren gesummt, die LEDs leuchten im Takt dazu.
Vielleicht errät jemand, was es für ein Stück ist? :)
/**
* @brief Play a melody from J. S. Bach.
* Push the left sensor to modify the speed.
* Push the right sensor to modify the sound volume.
*
* The sound quality depends on the underground, how many mechanical parts can vibrate
* on the robot, how the spheres are installed, the volume, etc..
*
* tip Hold the wheels with all fingers to feel the music :)
* This also may reduce rasping/scratchy sound.
*
*
* @author Oliver G.
* @date 2011-10-24
* @version 1.0
*/
#include <nibobee/iodefs.h>
#include <nibobee/led.h>
#include <nibobee/delay.h>
#include <nibobee/sens.h>
#include <nibobee/motpwm.h>
#include <math.h>
volatile uint8_t pulse; // helper for timing
uint16_t noteCnt; // current note of the melody
uint16_t beeperVolume;
uint8_t beeperActive;
uint16_t speed; // length of one note in ms (so actually 1/speed)
void playNote(uint8_t note);
void playNoteTime(uint8_t note, uint16_t time);
void playScales();
void initBeeper();
void listenSensorInput();
// Note names as used by european musicians. a1 = a' = 440 Hz
// (x)es names are missing, but you know that cis' = des' etc.
enum {
_C, _Cis, _D, _Dis, _E, _F, _Fis, _G, _Gis, _A, _Ais, _H,
_c, _cis, _d, _dis, _e, _f, _fis, _g, _gis, _a, _ais, _h,
c1, cis1, d1, dis1, e1, f1, fis1, g1, gis1, a1, ais1, h1,
c2, cis2, d2, dis2, e2, f2, fis2, g2, gis2, a2, ais2, h2,
c3, cis3, d3, dis3, e3, f3, fis3, g3, gis3, a3, ais3, h3, c4
};
// frequencies for _c to _h, the remaining notes will be computed
float freqTable[] = {
130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94
};
// Some nice melody from J.S. Bach!
// we don't need information about the note length,
// cause we can recognize this melody with equal note lengths
uint8_t melody[] = {
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, d1, a1, d2, f2, a1, d2, f2, c1, d1, a1, d2, f2, a1, d2, f2,
_h, d1, g1, d2, f2, g1, d2, f2, _h, d1, g1, d2, f2, g1, d2, f2,
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, e1, a1, e2, a2, a1, e2, a2, c1, e1, a1, e2, a2, a1, e2, a2,
c1, d1, fis1, a1, d2, fis1, a1, d2, c1, d1, fis1, a1, d2, fis1, a1, d2,
_h, d1, g1, d2, g2, g1, d2, g2, _h, d1, g1, d2, g2, g1, d2, g2,
_h, c1, e1, g1, c2, e1, g1, c2, _h, c1, e1, g1, c2, e1, g1, c2,
_a, c1, e1, g1, c2, e1, g1, c2, _a, c1, e1, g1, c2, e1, g1, c2,
_d, _a, d1, fis1, c2, d1, fis1, c2, _d, _a, d1, fis1, c2, d1, fis1, c2,
_g, _h, d1, g1, h1, d1, g1, h1, _g, _h, d1, g1, h1, d1, g1, h1,
_g, _ais, e1, g1, cis2, e1, g1, cis2, _g, _ais, e1, g1, cis2, e1, g1, cis2,
_f, _a, d1, a1, d2, d1, a1, d2, _f, _a, d1, a1, d2, d1, a1, d2,
_f, _gis, d1, f1, h1, d1, f1, h1, _f, _gis, d1, f1, h1, d1, f1, h1,
_e, _g, c1, g1, c2, c1, g1, c2, _e, _g, c1, g1, c2, c1, g1, c2,
_e, _f, _a, c1, f1, _a, c1, f1, _e, _f, _a, c1, f1, _a, c1, f1,
_d, _f, _a, c1, f1, _a, c1, f1, _d, _f, _a, c1, f1, _a, c1, f1,
_G, _d, _g, _h, f1, _g, _h, f1, _G, _d, _g, _h, f1, _g, _h, f1,
_c, _e, _g, c1, e1, _g, c1, e1, _c, _e, _g, c1, e1, _g, c1, e1,
c1 // melody shortened here...
};
int main() {
motpwm_init();
led_init();
sens_init();
initBeeper(); // (i'm used to camel case naming...)
speed = 130;
beeperVolume = 500;
playScales();
uint8_t i = 3;
while (i-- > 0) {
// short pause
beeperActive = 0;
delay(500);
beeperActive = 1;
noteCnt = 0;
while (noteCnt < sizeof(melody)) {
playNote(melody[noteCnt]);
noteCnt++;
}
delay(4 * speed); // hold last note of the melody
speed -= 20; // play melody a bit faster next time
}
beeperActive = 0;
delay(100);
disable_interrupts();
return 0;
}
/**
* Listen for some user/sensor input.
*/
void listenSensorInput() {
if (sens_getLeft()) {
speed += 10 * sens_getLeft();
while (sens_getLeft());
}
if (sens_getRight()) {
beeperVolume += 100 * sens_getRight();
while (sens_getRight());
}
}
/**
* Play the given note and hold it for the time defined in global var: speed.
*/
void playNote(uint8_t note) {
playNoteTime(note, speed);
}
/**
* Play the given note for the given time (milliseconds).
*/
void playNoteTime(uint8_t note, uint16_t time) {
uint8_t octave = note / 12;
float frequency = freqTable[note%12] * (1<<octave);
// set prescaler and compare value which will trigger interrupt
if (octave == 0) {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS02); // set prescaler to 1024
OCR0 = roundf( (F_CPU / 1024.0f) / frequency) -1;
} else if (octave <= 2) {
TCCR0 = (1<<WGM01) | (1<<CS02); // set prescaler to 256
OCR0 = roundf( (F_CPU / 256.0f) / frequency) -1;
} else {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS01); // set prescaler to 64
OCR0 = roundf( (F_CPU / 64.0f) / frequency) -1;
}
delay(time);
/* Uncomment this code for a little pause between the notes
TCCR0 = 0;
motpwm_setLeft(0);
motpwm_setRight(0);
delay(time/3); */
listenSensorInput();
}
/**
* Play some standard scales for sound check.
*/
void playScales() {
// chromatic scale
for (int i = 0; i < 5 * 12; i++)
playNoteTime(i, 20);
// 4 octaves c major scale
uint8_t cMajorScale[] = {
_c, _d, _e, _f, _g, _a, _h,
c1, d1, e1, f1, g1, a1, h1,
c2, d2, e2, f2, g2, a2, h2,
c3, d3, e3, f3, g3, a3, h3, c4
};
for (int i = 0; i < sizeof(cMajorScale); i++)
playNoteTime(cMajorScale[i], 100);
}
/**
* Config timer 0 and set beeper active.
*/
void initBeeper() {
TCCR0 = (1<<WGM01); // set CTC modus
TCCR0 |= (1<<CS02); // set prescaler to 256
OCR0 = (F_CPU/256) / 440 -1; // (value overwritten later)
TIMSK |= (1<<OCIE0); // allow compare interrupt
beeperActive = 1;
enable_interrupts();
}
/**
* Compare interrupt handler
* Is called if TCNT0 = OCR0
*/
ISR (TIMER0_COMP_vect) {
if (beeperActive) {
// let the motor turn left and right quickly to create some noise
// the led_set() calls are just added to create some light effect sync. to the melody
// the noteCnt % 8 distinction is also just for an effect - so deep notes are played on left,
// higher notes on the right motor
if (pulse++ % 2 == 0) {
if (noteCnt % 8 <= 1 ) {
led_set(3, 0);
led_set(2, 0);
led_set(noteCnt % 2, 1);
led_set(!(noteCnt % 2) , 0);
motpwm_setLeft(beeperVolume);
motpwm_setRight(0);
} else {
led_set(noteCnt % 2 + 2, 1);
led_set(!(noteCnt % 2) + 2, 0);
led_set(0, 0);
led_set(1, 0);
motpwm_setRight(beeperVolume);
motpwm_setLeft(0);
}
} else {
if (noteCnt % 8 <= 1) {
motpwm_setLeft(-beeperVolume);
motpwm_setRight(0);
} else {
motpwm_setRight(-beeperVolume);
motpwm_setLeft(0);
}
}
} else {
motpwm_setLeft(0);
motpwm_setRight(0);
}
}
Für Ideen, Anregungen, Verbesserungsvorschläge zum Programm/Code habe ich jederzeit ein offenes Ohr.
Das Projekt ist auch hier mit Source und Binary online: http://roboter.cc/index.php?option=com_nicaiwci&view=project&projectid=294
Viel Spaß und schöne Grüße,
Oliver G.
habe eine Melodie von J. S. Bach für den NIBObee umgesetzt. Die Melodie wird von den Motoren gesummt, die LEDs leuchten im Takt dazu.
Vielleicht errät jemand, was es für ein Stück ist? :)
/**
* @brief Play a melody from J. S. Bach.
* Push the left sensor to modify the speed.
* Push the right sensor to modify the sound volume.
*
* The sound quality depends on the underground, how many mechanical parts can vibrate
* on the robot, how the spheres are installed, the volume, etc..
*
* tip Hold the wheels with all fingers to feel the music :)
* This also may reduce rasping/scratchy sound.
*
*
* @author Oliver G.
* @date 2011-10-24
* @version 1.0
*/
#include <nibobee/iodefs.h>
#include <nibobee/led.h>
#include <nibobee/delay.h>
#include <nibobee/sens.h>
#include <nibobee/motpwm.h>
#include <math.h>
volatile uint8_t pulse; // helper for timing
uint16_t noteCnt; // current note of the melody
uint16_t beeperVolume;
uint8_t beeperActive;
uint16_t speed; // length of one note in ms (so actually 1/speed)
void playNote(uint8_t note);
void playNoteTime(uint8_t note, uint16_t time);
void playScales();
void initBeeper();
void listenSensorInput();
// Note names as used by european musicians. a1 = a' = 440 Hz
// (x)es names are missing, but you know that cis' = des' etc.
enum {
_C, _Cis, _D, _Dis, _E, _F, _Fis, _G, _Gis, _A, _Ais, _H,
_c, _cis, _d, _dis, _e, _f, _fis, _g, _gis, _a, _ais, _h,
c1, cis1, d1, dis1, e1, f1, fis1, g1, gis1, a1, ais1, h1,
c2, cis2, d2, dis2, e2, f2, fis2, g2, gis2, a2, ais2, h2,
c3, cis3, d3, dis3, e3, f3, fis3, g3, gis3, a3, ais3, h3, c4
};
// frequencies for _c to _h, the remaining notes will be computed
float freqTable[] = {
130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94
};
// Some nice melody from J.S. Bach!
// we don't need information about the note length,
// cause we can recognize this melody with equal note lengths
uint8_t melody[] = {
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, d1, a1, d2, f2, a1, d2, f2, c1, d1, a1, d2, f2, a1, d2, f2,
_h, d1, g1, d2, f2, g1, d2, f2, _h, d1, g1, d2, f2, g1, d2, f2,
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, e1, a1, e2, a2, a1, e2, a2, c1, e1, a1, e2, a2, a1, e2, a2,
c1, d1, fis1, a1, d2, fis1, a1, d2, c1, d1, fis1, a1, d2, fis1, a1, d2,
_h, d1, g1, d2, g2, g1, d2, g2, _h, d1, g1, d2, g2, g1, d2, g2,
_h, c1, e1, g1, c2, e1, g1, c2, _h, c1, e1, g1, c2, e1, g1, c2,
_a, c1, e1, g1, c2, e1, g1, c2, _a, c1, e1, g1, c2, e1, g1, c2,
_d, _a, d1, fis1, c2, d1, fis1, c2, _d, _a, d1, fis1, c2, d1, fis1, c2,
_g, _h, d1, g1, h1, d1, g1, h1, _g, _h, d1, g1, h1, d1, g1, h1,
_g, _ais, e1, g1, cis2, e1, g1, cis2, _g, _ais, e1, g1, cis2, e1, g1, cis2,
_f, _a, d1, a1, d2, d1, a1, d2, _f, _a, d1, a1, d2, d1, a1, d2,
_f, _gis, d1, f1, h1, d1, f1, h1, _f, _gis, d1, f1, h1, d1, f1, h1,
_e, _g, c1, g1, c2, c1, g1, c2, _e, _g, c1, g1, c2, c1, g1, c2,
_e, _f, _a, c1, f1, _a, c1, f1, _e, _f, _a, c1, f1, _a, c1, f1,
_d, _f, _a, c1, f1, _a, c1, f1, _d, _f, _a, c1, f1, _a, c1, f1,
_G, _d, _g, _h, f1, _g, _h, f1, _G, _d, _g, _h, f1, _g, _h, f1,
_c, _e, _g, c1, e1, _g, c1, e1, _c, _e, _g, c1, e1, _g, c1, e1,
c1 // melody shortened here...
};
int main() {
motpwm_init();
led_init();
sens_init();
initBeeper(); // (i'm used to camel case naming...)
speed = 130;
beeperVolume = 500;
playScales();
uint8_t i = 3;
while (i-- > 0) {
// short pause
beeperActive = 0;
delay(500);
beeperActive = 1;
noteCnt = 0;
while (noteCnt < sizeof(melody)) {
playNote(melody[noteCnt]);
noteCnt++;
}
delay(4 * speed); // hold last note of the melody
speed -= 20; // play melody a bit faster next time
}
beeperActive = 0;
delay(100);
disable_interrupts();
return 0;
}
/**
* Listen for some user/sensor input.
*/
void listenSensorInput() {
if (sens_getLeft()) {
speed += 10 * sens_getLeft();
while (sens_getLeft());
}
if (sens_getRight()) {
beeperVolume += 100 * sens_getRight();
while (sens_getRight());
}
}
/**
* Play the given note and hold it for the time defined in global var: speed.
*/
void playNote(uint8_t note) {
playNoteTime(note, speed);
}
/**
* Play the given note for the given time (milliseconds).
*/
void playNoteTime(uint8_t note, uint16_t time) {
uint8_t octave = note / 12;
float frequency = freqTable[note%12] * (1<<octave);
// set prescaler and compare value which will trigger interrupt
if (octave == 0) {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS02); // set prescaler to 1024
OCR0 = roundf( (F_CPU / 1024.0f) / frequency) -1;
} else if (octave <= 2) {
TCCR0 = (1<<WGM01) | (1<<CS02); // set prescaler to 256
OCR0 = roundf( (F_CPU / 256.0f) / frequency) -1;
} else {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS01); // set prescaler to 64
OCR0 = roundf( (F_CPU / 64.0f) / frequency) -1;
}
delay(time);
/* Uncomment this code for a little pause between the notes
TCCR0 = 0;
motpwm_setLeft(0);
motpwm_setRight(0);
delay(time/3); */
listenSensorInput();
}
/**
* Play some standard scales for sound check.
*/
void playScales() {
// chromatic scale
for (int i = 0; i < 5 * 12; i++)
playNoteTime(i, 20);
// 4 octaves c major scale
uint8_t cMajorScale[] = {
_c, _d, _e, _f, _g, _a, _h,
c1, d1, e1, f1, g1, a1, h1,
c2, d2, e2, f2, g2, a2, h2,
c3, d3, e3, f3, g3, a3, h3, c4
};
for (int i = 0; i < sizeof(cMajorScale); i++)
playNoteTime(cMajorScale[i], 100);
}
/**
* Config timer 0 and set beeper active.
*/
void initBeeper() {
TCCR0 = (1<<WGM01); // set CTC modus
TCCR0 |= (1<<CS02); // set prescaler to 256
OCR0 = (F_CPU/256) / 440 -1; // (value overwritten later)
TIMSK |= (1<<OCIE0); // allow compare interrupt
beeperActive = 1;
enable_interrupts();
}
/**
* Compare interrupt handler
* Is called if TCNT0 = OCR0
*/
ISR (TIMER0_COMP_vect) {
if (beeperActive) {
// let the motor turn left and right quickly to create some noise
// the led_set() calls are just added to create some light effect sync. to the melody
// the noteCnt % 8 distinction is also just for an effect - so deep notes are played on left,
// higher notes on the right motor
if (pulse++ % 2 == 0) {
if (noteCnt % 8 <= 1 ) {
led_set(3, 0);
led_set(2, 0);
led_set(noteCnt % 2, 1);
led_set(!(noteCnt % 2) , 0);
motpwm_setLeft(beeperVolume);
motpwm_setRight(0);
} else {
led_set(noteCnt % 2 + 2, 1);
led_set(!(noteCnt % 2) + 2, 0);
led_set(0, 0);
led_set(1, 0);
motpwm_setRight(beeperVolume);
motpwm_setLeft(0);
}
} else {
if (noteCnt % 8 <= 1) {
motpwm_setLeft(-beeperVolume);
motpwm_setRight(0);
} else {
motpwm_setRight(-beeperVolume);
motpwm_setLeft(0);
}
}
} else {
motpwm_setLeft(0);
motpwm_setRight(0);
}
}
Für Ideen, Anregungen, Verbesserungsvorschläge zum Programm/Code habe ich jederzeit ein offenes Ohr.
Das Projekt ist auch hier mit Source und Binary online: http://roboter.cc/index.php?option=com_nicaiwci&view=project&projectid=294
Viel Spaß und schöne Grüße,
Oliver G.