Music to my Sensors
I love music and often spend hours in the robot lab playing guitar. It's time to combine music and robotics with another fun build of the MRK-2.
We're going to build a theremin!
This is another perfect project to introduce robotics to beginners using the MRK-2. We'll learn about some cool new functions and play with math.
Difficulty:Beginner
Time: 15 minutes
Kit: MRK-2
Source Code: https://github.com/Robot-Scholar/theremin
WHAT IS A THEREMIN?
Good question! I'm glad you asked.
A theremin is a cool electronic instrument that is played by a performer without requiring any physical contact. Real theremins usually allow the performer to control the tone with one hand and the pitch with the other. Because we're using the MRK-2 with it's single HC-SR04 ultrasonic sensor, we're going to start with a mini-theremin that only uses one hand for tone.
THE SETUP
This is another build that doesn't require the motors and will be recognizable to anyone that worked through the Guard Dog project. This project will involve having the MRK-2 sitting motionless with the sensors pointing up in the air.
To begin, open up your Arduino code editor and create a new project. Our code setup will remain simple and all we need to do is define the pins we'll use for our musical instrument.
#define led 13
#define buzzer 3
#define echoPin A0
#define pingPin 10
int toneCounter = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(pingPin, OUTPUT);
pinMode(echoPin, INPUT);
}
We also need to create an integer (a variable that stores whole numbers) so that we can shut off the theremin whenever we take our hands away.
PERFORMANCE LOOP
Things start to get interesting inside of our loop() function. We want our theremin robot to look for an object with the ultrasonic sensor and report back the distance in centimeters.
Once we have this distance value, we need to play a different tone depending on how far up our hands are from the robot. To play the tone, we'll be using the aptly named built-in tone() function that we've used in our Guard Dog program, but now we'll want to change the tone and fluidly change that note as we wave our hands up and down inside the robot's field of view.
void loop() {
// put your main code here, to run repeatedly:
long dist = msToCm(ping());
if ( dist < 100.00 ) {
toneCounter = 0;
// 1 == min distance in cm
// 100 == max distance in cm
// 1500 == max frequency
// 500 == min frequency
int pitch = map(dist, 1, 100, 1568, 784);
tone(buzzer, pitch);
}
}
Through a little bit of experimentation, I've found that the sweet spot for this range of motion is between 1 cm and 100 cm. You can change these to suit your preferences, but 1-100 feels right.
Once we have this distance, what are we going to do with it?
Exploring the frequencies in Pitches.h, I felt like it would be pleasant to move between G5 (784) and G6 (1568) and have my robot operate inside a single octave. But you should pick out some notes from there and experiment with however you want your robot theremin to sound.
With these two frequencies in mind, we need a graceful way to convert our distances from 1-100 in centimeters to some value on the scale of 784 to 1568. Luckily, this conversion is really straightforward with the Arduino map() function. This function takes our value (dist) and translates it to a frequency that fits between 784 and 1568.
You'll notice in our map() function, we have 1568 listed before 784. This will let us flip the scale so that the closer our hand moves to the robot, the higher the note the robot will play. If we wanted the high notes to be played as we moved our hand up, we'd just have to swap these two values.
Once we have this frequency value, all we have to do is pass it to the tone() function and enjoy the note!
PREVENTING CONSTANT PLAYING
The last thing we'll need to do is check to see if our hand is not inside the range of the musical robot. If the distance being returned is greater than 100 cm, we can add 1 to our toneCounter variable. Once that number reaches 100, we can call notone() and turn off the buzzer. This simple little trick will keep our robot quiet while we're not playing with it.
void loop() { // put your main code here, to run repeatedly: long dist = msToCm(ping());
if ( dist < 100.00 ) {
toneCounter = 0;
// 1 == min distance in cm
// 100 == max distance in cm
// 1500 == max frequency
// 500 == min frequency
int pitch = map(dist, 1, 100, 1568, 784);
tone(buzzer, pitch);
} else {
toneCounter++;
if ( toneCounter == 100 ) {
toneCounter = 0;
noTone(buzzer);
}
}
}
NEXT STEPS AND EXPERIMENTATION
That's all there is to it! This is the base of a fun little performance robot that you can use for fun experimentation.
If you're interested in taking this further, I'd recommend playing with the IR sensors located on the base of the robot and getting your second hand involved in your musical genius. You can use those sensors and do things like shift the octave up or down, or control the output style. The sky's the limit!