29
ENGDUINO EXAMPLES: THEREMIN The theremin is a weird and wonderful electronic instrument that requires no physical contact. Have a listen to a program about them at: http://www.bbc.co.uk/programmes/b0076nqv The theremin was invented in 1920 by Léon Theremin, an early Russian electronic engineer. It is played by moving one’s hands near two antennas – the first controls the volume of the output and the second the pitch. For those that are musical it is worth knowing that the Theremin inspired Robert Moog to invent the synthesiser, so, although it’s a little-used instrument, it has had a powerful effect on the history of music. THE PROJECT In this project, we will use the light sensor to control the frequency of a tone. We could use a second Engduino to control the volume, but that requires a bit more hardware and it’s the principles that matter here. You will need an Engduino and a little piezo-electric speaker. Plug the speaker into the Engduino’s expansion bus – to the connections marked IO_0 (third from top) and GND (bottom). The project itself falls into two parts: making a tone at a given frequency and controlling that frequency using the light sensor. PRODUCING A TONE A tone is a pure sine wave. A sine wave of 440Hz is the A above middle C, commonly used for tuning.

Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

ENGDUINO EXAMPLES: THEREMIN

The theremin is a weird and wonderful electronic instrument that requires no physical contact. Have a listen to a program about them at: http://www.bbc.co.uk/programmes/b0076nqv

The theremin was invented in 1920 by Léon Theremin, an early Russian electronic engineer. It is played by moving one’s hands near two antennas – the first controls the volume of the output and the second the pitch.

For those that are musical it is worth knowing that the Theremin inspired Robert Moog to invent the synthesiser, so, although it’s a little-used instrument, it has had a powerful effect on the history of music.

THE PROJECT

In this project, we will use the light sensor to control the frequency of a tone. We could use a second Engduino to control the volume, but that requires a bit more hardware and it’s the principles that matter here.

You will need an Engduino and a little piezo-electric speaker. Plug the speaker into the Engduino’s expansion bus – to the connections marked IO_0 (third from top) and GND (bottom).

The project itself falls into two parts: making a tone at a given frequency and controlling that frequency using the light sensor.

PRODUCING A TONE

A tone is a pure sine wave. A sine wave of 440Hz is the A above middle C, commonly used for tuning.

Mixtures of different sine waves are what gives us the complex sounds we hear from musical instruments. Pure tones on their own sound artificial and electronic because they don’t happen in nature.

Page 2: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

Unfortunately, our Engduino can’t even generate a sine wave – it is a digital system so can only generate square waves (0s and 1s). For our purposes, this doesn’t matter much – in fact a square wave can be represented by a series of mixed sine waves so it is not quite the same as a pure tone, but it’s close enough for us.

WRITING OUR OWN CODE TO MAKE A TONE.

If you’ve connected the speaker up as suggested, you have connected it to digital pin D5. To make a very boring sound, we can switch the output from 0 to 1 and back again at a known frequency. For example:

int speaker = 5; // Speaker connected to digital pin 5

void setup(){ pinMode(speaker, OUTPUT); // sets the digital pin as output}

void loop(){ digitalWrite(speaker, HIGH); // sets the speaker pin high delay(1); // waits for a 1ms digitalWrite(speaker, LOW); // sets the speaker pin low delay(1); // waits for a 1ms}

In setup, we set the digital pin to be an output. Then we loop setting it high, waiting for 1ms, setting it low, waiting for 1ms, and continuing. What frequency note would you expect this to be? See what happens when you change the delay values.

AN ALTERNATIVE

Fortunately, someone has done the hard work and written a library for us that will generate tones. The library uses a feature built in to the microprocessor called pulse width modulation (PWM) – in our case this just allows us to generate tones more accurately than we could do ourselves.

There are two calls – one to make a tone, or make it for a given amount of time; and the second to stop a tone being played:

tone(speaker, frequency) tone(speaker, frequency, duration)

noTone(speaker)

Write a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right. See if you can make it play a tune. HINT: the frequencies of notes are given at the bottom of the page at http://arduino.cc/en/Tutorial/tone.

Page 3: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

GETTING INPUT FROM THE LIGHT SENSOR

You should work through the light sensor worksheet.

Print the light values to the screen. Even if keep everything as constant as possible – don’t move the Engduino, sit still, etc., is the value a constant? If we use this value to change the sound, what kind of thing do you think we’ll hear?

RESCALING THE INPUT

The input from the light sensor ranges, in theory, from 0-1023. In practice it will rarely reach 1023 and, if you’re just using the illumination in the room, the maximum in practice might only be, say, 700 (you’ll need to measure this). Likewise, the minimum might not be zero when it’s fully covered – try it.

Choose a range of frequencies you’d like your theremin to cover. Let’s say that’s 50Hz to 5000Hz.

So, in my case, I would want the following:

See if you can work out how a way of calculating the output frequency for a given value of light input.

Try it – print the original and scaled values to the screen using Serial.print

CONNECTING THE TWO

We now need to connect the light sensor to the speaker.

Use the rescaled value you’ve just generated to set the tone on the speaker. How does it sound?

Awful, in all probability. And there are two problems. The first is that your hand has to get very very close to the light sensor to get low tones and the second is that it just sounds awful. Let’s fix the second.

PLEASE STOP, YOU’RE HURTING MY EARS

The problem with the tone that never seems to stand still comes from the fact that the light sensor value doesn’t stand still – it is noisy, partly because the lights flicker, albeit faster than you can see. So we need to filter the value – to smooth it out over time.

To do that, we might make use of some maths. We could read the sensor and make an average out of the last n readings, where n is a number you choose. This is called a simple moving average and, mathematically, it’s represented by the formula:

Input from

Output

0 700

50 5000

Page 4: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

out i=¿i+¿i−1+¿i−2+¿i−3+…+¿i−n+1

n

Try to implement this. To do so, you’ll need to know what an array is.

ASIDE: ARRAYS

An array is a data structure used in just about all programming languages. In our case, it’s a numbered collection of things of the same type with a fixed maximum size. In essence it’s a set of boxes into which we can put values – each box has a number, starting at 0 and going up.

Say we needed to keep the last 3 values of a variable, then we create an array of length 3. Let’s say these values are floating point values rather than integers and we want the name of the array to be ‘buffer’. We declare the array immediately after the #include directives in the following way:

#define BUFFERSIZE 3float buffer[BUFFERISZE];

This creates an array of 3 boxes (labelled 0, 1, and 2) in which we can store floating point numbers. But, before we can use this for our purposes, we need to know where to put the latest sensor reading. For this we need another variable that will tell us which of those spaces should contain the value we have just read from the sensor (i.e. in box 0, 1 or 2) – we’ll call this the index variable. We will calculate the average of all the readings stored in buffer and, if we keep moving the index value on, we can make sure that we always have the last three values from the sensor in the array. After some time, let’s imagine we have to deal with reading 27. Before we put it in, the buffer should contain readings 24, 25 and 26:

After we put in 27, we want it to contain:

When we get reading 28, this gets put into box 0…

And so on. We just need to organise that the index variable always points to the next box into which we should put a reading. To achieve this, add the following after the above two lines – it creates a variable ‘index’ and sets its value to be 0 (the first location in buffer).

int index = 0;

Now let’s look at how to use this in calculating a simple moving average. In the loop() section of your code, you will need something that looks a bit like the following:

210

242625

index = 2

210

272625

index = 0

210

272628

index = 1

Page 5: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right
Page 6: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

void loop(){

…int sensorValue;int rescaledValue;float movingAverage;

...Get the light sensor value

buffer[index] = sensorValue;index = index + 1;if (index > BUFFERSIZE) index = 0;

movingAverage = 0; for (int i = 0; i < BUFFERSIZE; i++) movingAverage = movingAverage + buffer[i];movingAverage = movingAverage/BUFFERSIZE;

... Rescale the moving average value to the range we want

... and play the tone

delay(1);}

Give this a go….

BACK AGAIN

The longer the buffer we choose, the smoother the value will be, but the longer the instrument takes to respond to a change. Welcome to engineering.

Experiment with this. Why does the instrument sound odd for a short while after you reset it and what could we do to change that?

RESCALING THE INPUT REVISITED

One of the reasons that a simple scaling doesn’t work so well – much of the change happens close to the light sensor – is that the input is not linear in the distance your hand is from the sensor. Take a tape measure and work out what the (averaged) light sensor readings are for each distance. Plot this as a curve.

Can you figure out a way of changing your rescaling so that we can make changes (even a bit) further away than at present?

Page 7: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

ENGDUINO EXAMPLES: THE GIMBAL

In this example we’ll build a simple motorised gimbal. Gimbals are an ancient device used to stabilise, for example, compasses on board ships. In short they are designed so that when the ship moves, the compass stays flat.

Recently, with the introduction of small motors and small cameras, motorised gimbals have been used in photography – both for handheld cameras and for those mounted on, say, helicopters or UAVs. In these, a sensor detects changes movement of the person/helicopter and causes the motor to move the camera to compensate. And so the picture stays steady.

We will use the accelerometer to detect where down is and a servo motor to move the Engduino so that it stays in the same orientation. To do this, we’ll have to learn a little control theory – and you will undoubtedly find out that it requires a bit of time and effort to make a good(ish) control system.

To build this project we need to do two things: (i) figure out which direction is down relative to how the Engduino is being held; and (ii) move the servo motor to compensate. The second is itself two parts: (iia) learn how to move the servo motor to a given place; (iib) choose how much to move it in one go.

WHICH WAY IS DOWN?

You should complete the accelerometer handout before proceeding.

The accelerometer returns three values – x, y, and z. If we’re not accelerating the device, then the values are due exclusively to gravity and we can figure out what direction gravity is in just from the values returned.

First, we need to know what direction is what. Look at the x, y, z values as you move the Engduino in space. Check that the directions on the picture match the direction you think gives a positive value for each axis.

x

y

z (out of the board)

Page 8: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

So, let’s make the problem a bit easier. If we hold the Engduino vertically (so the E always faces out from your chest), then the z axis will never have any acceleration due to gravity, irrespective of how the Engduino is rotated. So we only need to think about the x and y axes.

There is a useful function for working out angles from x and y values. The function is an arctangent – the opposite of a tangent.

In Arduino code, the arctan function is represented by something called atan2(y,x) (and it is important to remember the 2): it’s a slightly more sophisticated form of arctan that gives a value between -180° and +180°

You need to add:

#include <math.h>

to the top part of the file with the other includes, and then you can use the atan2 function:

angle_in_radians = atan2(accelerations[1], accelerations[0]);

Amend the code you wrote for the accelerometer to print out this angle, then rotate the Engduino (remembering to hold it so the E always faces out from your chest) so the angle changes.

The number seems to go from about -3.14 to +3.14 – what’s happening? Well, this is an angle in radians, and that’s perhaps something you aren’t used to, but it is no big deal – it is just another way of writing angles that happens to be useful to mathematicians. There are 2π radians in a circle – put another way 2π radians is the same as 360° or π radians is the same as 180°. So when we see numbers that go from -3.14 (i.e. –π) to 3.14 (i.e. + π), what we’re actually seeing is the number going from -180° to +180°. If you want to convert between an angle in radians and one in degrees we write the following code:

angle_in_degrees = angle_in_radians * 180/PI;

Note the capital letters for PI. Try it.

So, with the E the right way up and out from your chest, what angle would you expect? (Answer -90, but why?)

θ

x

y

tan θ = y/x

θ = arctan(y/x)

Page 9: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

MOTORS

Next we’re going to take a look at the servo motor. These are used in radio controlled vehicles and aeroplanes to control, for example, the angle of the rudder of a boat, or the ailerons on a plane. They are a motor we can set to a certain angle – in this case ranging from 0° to 180°– only half a circle.

The motors are set using what is called a pulse width modulation signal (PWM).

WRITING OUR OWN CODE TO DRIVE THE MOTORS

We can write a program to generate these by hand. Get the assistant to connect the device up for you. The servo motor control signal is connected to digital pin 5 on the Engduino.

int motor = 5; // Motor connected to digital pin 5

void setup(){ pinMode(motor, OUTPUT); // sets the digital pin as output}

void loop(){ digitalWrite(motor, HIGH); // sets the LED on delayMicroseconds(1000); // waits for 1ms digitalWrite(motor, LOW); // sets the LED off delayMicroseconds(19000); // waits for 19ms}

0

90

180

1ms

1.5ms

2ms

Time /ms 0 20

Page 10: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

This generates the first square wave (on for 1000μs = 1ms off for 19000μs = 19ms). It won’t quite work to set it to location zero because there are some extra delays in the instructions that make the on-time a little more than 1ms.

Experiment – see what works.

AN ALTERNATIVE

Fortunately, someone has done the hard work and written a library for us that will move the servo motor. The library the pulse width modulation (PWM) that is built into the microprocessor.

To use the library we have to ‘attach’ ourselves to the servo in the setup() routine and then we can command it to go to a particular angle by ‘write’ing a position in degrees. The code below is an example from the authors of the library – it can be found at http://arduino.cc/en/Tutorial/Sweep to save you retying it (but you must remember to change the pin to 5). See what it does.

// Sweep// by BARRAGAN <http://barraganstudio.com> // This example code is in the public domain.

#include <Servo.h> Servo myservo; // create servo object to control a servo // a maximum of eight servo objects can be created int pos = 0; // variable to store the servo position void setup() { myservo.attach(5); // attaches the servo on pin 5 to the servo object } void loop() { for (pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees { // in steps of 1 degree myservo.write(pos); // tell servo to go to position in pos delay(15); // waits 15ms for the servo to move }

for (pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees { myservo.write(pos); // tell servo to go to position in pos delay(15); // waits 15ms for the servo to move } }

So now we can set the servo to a known angle. In reality, we don’t necessarily quite get the full 0-180 degree range, but we can let that go.

Page 11: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

MAKING A GIMBAL

Ask the class leader to attach the servo to the Engduino if it is not already attached. This just needs to be done so that the Engduino can move in the right way (set the servo to angle zero and then attach the servo with the top facing the same direction as the E).

Our goal is to create a system that ensures that the Engduino is always facing the right way up, no matter how we move it (with the bounds of what the motor can do). We know ‘the right way up’ is to have an angle of -90°. In control terms, this is called the ‘setpoint’.

If the angle changes because we move the Engduino, then we need to make the servo move in such a way as to compensate for that change. We do that by calculating an error between the setpoint and the current angle.

double error = setpoint - angle;

ASIDE: CONTROL

If we have an error, then know exactly how far we need to move the servo to get to the correct position, right? All we would have to do is to write some code in the setup routine that says:

myservo.attach(5); // attaches the servo on pin 5 to the servo object myservo.write(pos);

And in the loop that says:

pos += error;pos = constrain(pos, 0, 180); myservo.write(pos);delay(50);

The call to ‘constrain’ just ensures that the value always lies between 0 and 180 – the only sensible range of inputs to our servo.

Try it – see what happens, but be prepared to hang on. Unless you’re supremely lucky the system will be unstable. Let’s try something different - so called proportional control. What we do is to multiply the error by a number less than 1 (i.e. a proportion) – say 0.1. Replace the first line above by:

double Kp = 0.1;pos += error * Kp;

Is it more stable? How about for different values of Kp, say 0.3? Keeping it in the same orientation, just shake it slightly and see what happens. In general, the higher the value of Kp, the more quickly it will get to the setpoint, but the less stable it will be.

What about more sophisticated control?

Well, a common form of controller is a PID controller – proportional, integral, differential.

Proportional control is what we’ve just done – it depends on a proportion of the current error.

Page 12: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

Integral control adds up error over time. The bigger the accumulated error, the bigger the control input (e.g. the more off course a ship has become in spite of proportional control, the more sharply we should steer)

Differential control depends on the rate of change. If we get a sudden change in something then we guess that that change will persist into the future – it’s a guess about what might happen.

Pseudocode would look something like the following:

error = setpoint - sensor_value;errorSum += (error * timeChange);errorChange = (error - lastErr) / timeChange;

p = Kp * error;i = Ki * errorSum;d = Kd * errorChange;

pos = pos + p + i + d;

lastErr = error;

You could code this up and try some parameters. What you are likely to find is that many parameters do not lead to sensible behaviour, and it takes a little while to get a set that is much good – reasonably stable and with a reasonably rapid response. Fortunately, in real life there is maths to help with all of this – and some tricks on implementation that make the results better… welcome to Engineering.

Control systems are used in all factories, cars, homes, in the production of electricity and the pumping of water, in rockets and in robots for surgery. Building them is a many many billion dollar business and there’s quite a lot to learn.

Take a look at the Arduino PID library http://playground.arduino.cc/Code/PIDLibrary - and, in particular, the detailed description of how to improve our beginners’ version of PID http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

Page 13: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

ENGDUINO EXAMPLES: COMMUNICATIONS

Humans have been using simple communications systems for centuries to send messages over a long distance, much further than the human voice can reach. Information was sent between signal towers on the Great Wall of China by using flashing lanterns at night or smoke signals during the day. Around 100 BC a Roman historian called Polybius invented a way of using numbers to represent the alphabet using a grid.

1 2 3 4 51 A B C D E2 F G H I/J L3 L M N O P4 Q R S T U5 V W X Y Z

Table 1- Polybius' Grid

Words can be spelled out using the grid reference of the letters so ‘A’ is 1,1 and ‘S’ is 4,3. The message “RED ROSE” is: (4,2) (1,5) (1,4) (4,2) (3,4) (4,3) (1,5). Polybius invented this scheme so that people could send a message using 2 torches. Imagine the sender holding a torch in each hand. Flashing the torch in the right hand to indicates the row of the letter in the grid. Flashing the torch in the left hand to indicates the column of the letter.

IN THIS PROJECT

You will learn how to send and receive secret messages using two Engduinos. You will transmit messages using the LEDs on one device and receive messages using the light sensor on the other. The point of this project is to:

learn about the way information is stored in a computer using binary,

explore how information is transmitted between one computer and another.

GETTING STARTED

Computers only understand a very simple and limited language composed of ‘0’s and ‘1’s. This is a binary number system which you have probably learned about already. It is very easy to generate

With another person:

One of you should encode a short, secret message using the Polybius Grid. Find a way of communicating your message to the other person without speaking. Let the other person decode the message.

Page 14: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

signals to represent this two-digit language, after all, we can think of the digit 0 as OFF and the digit 1 as ON. The 0 and 1 are known as ‘bits’.

Programming the Engduino to send and receive binary messages is quite complex but we can make it easier by breaking the project down into stages:

Stage 1. Make one Engduino talk by sending a binary signal.

Stage 2. Make the other Engduino listen by receiving a binary signal.

Stage 3. Synchronise the sender and receiver.

Stage 4. At the sender, convert a character in a message to a binary signal.

Stage 5. At the receiver, convert binary signal to a character in a message.

STAGE 1: SEND A BINARY SIGNAL WITH THE ENGDUINO

Complete the Traffic Lights tutorial before attempting this part of the project.

We have seen that you can communicate quite complex messages using a simple coding system like the Probius Grid. Our first task is to program one of the Engduinos to send a binary signal: ‘0’ (OFF) and a ‘1’ (ON) using the LEDs. We can use some of the code from the Traffic Lights tutorial to do this.

You are going to complete this project by writing your own code and by using some code we

have written for you.

Download the file containing the sketches you need from the Engduino website. The file is

called SendReceiveSketches.zip. Save it on the computer’s Desktop or somewhere

inside your Documents folder.

To ‘unzip’ the file, right click on it and choose option “Extract All …..”

Page 15: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

SEND A SIGNAL

Start the Arduino IDE. Open the sketch SendBinary.ino. Use File -> Open like this:

You can find this file in the SendBinary sketch in the folder you downloaded.

Now write some code to turn all the LEDs on for, say 1 second and then turn the LEDs off for 1 second repeatedly. You should add a definition for the length of time it takes to transmit a bit. Add this immediately after the #include directives in the following way

#define BIT_DURATION 1000 //Length of time (milliseconds) to transmit a bit

Then later in the main loop(), you can use this value like this:

delay(BIT_DURATION);

Don’t forget to save your program intermittently. Upload the program to the Engduino that will be the sender in your communications system.

Your Engduino is now transmitting a series of bits like this:

0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1

STAGE 2: RECEIVE A BINARY SIGNAL WITH THE LIGHT SENSOR

You should work through the Light Sensor worksheet.

The next step is to write some code for the Engduino receiver that will interpret the binary signal. The question we need to answer is: are the light sensor readings significantly different when the LEDs on the sending device are on and off?

Page 16: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right
Page 17: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

RECEIVE A SIGNAL

Open the file ReceiveBinary.ino which is in the ReceiveBinary folder.

Write some code to read the values from the light sensor and print out a message to the serial monitor repeatedly. You will need to upload your program to the second Engduino, the one you are using as a receiver. Make sure it is plugged into a USB port and that you have the correct COM port selected in the Arduino IDE.

The input from the light sensor ranges, in theory, from 0-1023. In practice it will rarely reach 1023 and, if you’re just using the illumination in the room, the maximum might only be, say, 700 (you’ll need to measure this). Likewise, the minimum might not be zero when it’s fully covered – try it. Shine the Engduino with the flashing LEDs directly at the light sensor on the receiver.

What is the light level when the LEDs are off?

What is the light level when the LEDs are on?

Add some more code to the receiver. If the light level is high then print a message to the serial monitor to show that you have received a ‘1’. Otherwise, if the light level is low then print a message to the serial monitor to show that you have received a ‘0’.

Congratulations! You have just created a communications system with a sender and a receiver.

STAGE 3: SYNCHRONISE THE SENDER AND RECEIVER

You should work through the Button worksheet.

Imagine that you have sent this binary message.

As

you can see, there are some repeated digits. In some places there are two, three or even more repeated 0’s or 1’s. How will the receiver know how many 0’s or 1’s it has received?

1 0 0 0 1 1 0 1 1 1 1 1 1 0 0 0 0 1 1 0 1 0 1 1 0 0 1 1

Page 18: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

In a computer system, all binary signals are synchronised using an internal clock. The hardware components in a computer use the clock to tell when to send a bit and when to receive a bit.

Our problem is more difficult to solve, we have two devices, a sender and receiver, and they don’t share a clock. We need to synchronise the sender and receiver so that:

1. The sender and receiver know when to start transmitting and receiving.

2. The sender and receiver know how long an LED will flash for each binary digit.

We are going to have to synchronise the sender and receiver using some kind of manual technique. One way that we can do this is to tell the Engduinos when to start by pressing the button on the back of each device. This may not be very accurate but let’s see if it’s accurate enough.

ADDING A START SIGNAL

Add some code to the sender and the receiver so that they don’t start sending or receiving until the button is pressed.

Now add a delay to the receiver so that it checks the light level every 1 second. Remember, the sender is sending a bit every second.

You are now at the point where you can send and receive a signal fairly reliably. Let’s do one more thing before we finish this stage. At the moment, our sender and receiver are synchronised as closely as they can be. Both start sending and receiving as soon as we press the button and both wait 1 second before sending and receiving again.

The diagram in Figure 1 shows what happens when the sender and receiver are synchronised accurately enough.

Page 19: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

The

Figure 1 - Sending and Receiving a Binary Digit

You can see that if there is a small delay at the receiver, things might be different. The receiver might not read the correct bit. To reduce the possibility of this happening you can add a small delay of 500 milliseconds to the receiver. Do this now, add the delay right after the code for waiting for the button press. This will ensure that the receiver reads the light sensor roughly in the middle of the transmission.

Next, we have to make that signal mean something – our message.

STAGE 4: TRANSLATE A LETTER OF THE ALPHABET INTO A BINARY SIGNAL

Transferring bits from one Engduino to the other is all very well but humans do not communicate in 0’s and 1’s; when we write things down we use an alphabet. Our next task is to write some code to translate letters of the alphabet into binary at the sender so that they are ready for transmission.

The coding system which is most often used to represent the alphabet is known as ASCII which stands for the American Standard Code for Information Interchange. At the time it was invented, ASCII was used to encode 128 characters: 0-9, a-z and A-Z and some punctuation symbols. Nowadays, ASCII has been superseded by UTF which stands for Universal Character Set, Transformation Format. UTF can accommodate many different alphabets and symbols such as Arabic and Kana, which is a Japanese script.

In ASCII, each character is represented as 7 or even 8 bits of binary. In this program we will use 7 bits. Table 1 contains the binary representations of the characters ‘A’ through to ‘E’.

English Binary

Page 20: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

AlphabetA 1000001B 1000010

C 1000011

D 1000100

E 1000101

Table 2 - ASCII to Binary Conversion

It would take a while to type in the ASCII conversion table into our program so we will use some code that exists already. As programmers, we use and re-use code regularly, after all there is no point in writing code yourself if someone else has already done it.

You have been given two extra sketches with your Sender and Receiver sketches called ASCII2Binary.ino and Binary2ASCII.ino. Take a look at the files. Even if you don’t understand the code yet, you will see something that looks like a lookup table near the top of each one.

These files contain some simple conversion utilities. As their names suggests, one will convert an ASCII character into seven binary digits. The other will convert seven binary digits into an ASCII character.

Before we can use these utilities, we will have to learn how to store our binary digits in an array. Let’s learn what an array is.

ASIDE: ARRAYS

An array is a data structure used in just about all programming languages. In our case, it’s a numbered collection of things of the same type with a fixed maximum size. In essence it’s a set of boxes into which we can put values – each box has a number, starting at 0 and going up.

Say we needed to store 7 binary digits, then we create an array of length 7. Let’s say we store these values in an array of integers and we want the name of the array to be ‘binaryValue’. We declare the array immediately after the #include directives in the following way:

#define ARRAYSIZE 7integer binaryValue[ARRAYSIZE];

This creates an array of 7 boxes (labelled 0, 1, 2, 3, 4, 5, 6) in which we can store integer numbers.

At the sender, we are going to translate an ASCII character to a set of binary digits then we are going to make the Engduino flash on and off for each digit.

001

0

0101

1 2 643 5

The letter ‘b’ in binary

Page 21: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

To do this, we need to go through each cell in the array in turn. For this we need another variable that will tell us which of those spaces, or boxes, contains the digit we’ll transmit next – we’ll call this the index variable.

We just need to organise that the index variable always points to the next box that we want to transmit. To achieve this, add the following after the above two lines – it creates a variable ‘index’ and sets its value to be 0 (the first location in buffer).

int index = 0;

Now let’s look at how to use this.

BACK AGAIN

In the loop() section of your sketch, you will need something that looks a bit like the code below:

void loop() { // // Wait until the button has been pressed. //

EngduinoButton.waitUntilPressed(); char nextCharacter = 'a'; // a character to transmit // // We have the next letter in our message, now lookup the binary value // using the method ASCII2Binary. // ASCII2Binary(nextCharacter, binaryValue);

for (int index = 0; index < ARRAYSIZE; index++) { if (binaryValue[index] == 1){ EngduinoLEDs.setAll(WHITE); } delay(BIT_DURATION); EngduinoLEDs.setAll(OFF); }

Give this a go…. add some print statements to your code using the Serial.print() function so that you can see what it is doing using the Serial monitor.

SENDING A MESSAGE CONTAINING SEVERAL CHARACTERS

Now that you know how to use arrays you can create one in which to store your simple message:

#define MESSAGESIZE 5

Page 22: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

char message[MESSAGESIZE]={'H', 'E', 'L', 'L', 'O'};

This time, our array contains characters. Add an array containing a message to your program. Use a for loop to go through each character in the message and translate it to a binary value.

STAGE 5: TRANSLATE A BINARY SIGNAL TO A LETTER OF THE ALPHABET

The final stage of this project is to collect 7 bits of binary at the receiver and translate them into an ASCII character.

Go back to editing the code for the receiver. In the same way as you did before, declare an array of integers, length 7. Let’s say we we want the name of the array to be ‘binaryValue’, again, we declare the array immediately after the #include directives in the following way:

#define ARRAYSIZE 7integer binaryValue[ARRAYSIZE];

Now edit your code so that you are using the array to store the binary signals you are collecting. Your code should look something like this:

void loop() {

int lightValue; // Wait until the button has been pressed. EngduinoButton.waitUntilPressed();

delay(BIT_DURATION / 2) // Wait for a short time // // Detect 7 bits // for (int i = 0; i < ARRAYSIZE; i++) {

lightValue = EngduinoLight.lightLevel(); if ( lightValue >= LIGHT_ON ) // Assume 1 received binaryValue[i] = 1; else binaryValue[i] = 0; // Assume 0 received

delay(BIT_DURATION); }

CONVERTING THE BINARY DIGITS TO A CHARACTER

Look at the sketch called Binary2ASCII, how do you think you should use it? Give it a go …..

Page 23: Engduino EXAMPLES: Theremin - UCL Computer … · Web viewWrite a second sketch to try it – using the frequency you thought the previous tone was at to check whether you’re right

WHAT NEXT?

In this tutorial you have covered the basic elements of all digital communications systems but there are several ways in which our communications system could be improved. You have probably noticed that sometimes the receiver does not receive the bit correctly. You could think about using a parity bit for this, take a look at the Section on Error Detection and Correction in the A-Level Computing Wikibook by Peter Kemp.