## Introduction

As you may have noted from previous lessons, sometimes the sensor reading function returns strange values. For example, an ultrasonic range finder reads (erroneous) really large distances from time to time, even when there is a near object in front of it. In this lesson we will learn some simple techniques that will help us to reduce the effects of the noise and false readings from the robot’s sensors. Also, we will introduce here some basic concepts about the analog to digital signal conversions used in Sparki.## What You’ll Need

- A Sparki.

## Analog to Digital Signal Conversions

Before start to work with Sparki’s sensors, let’s see some basic concepts about the way that our small robot receives information from the external world. As you may know, Sparki’s brain is a small digital microcontroller (MCU), specifically an Atmel ATMega32U4. And by digital we mean that in its inside, it deals with digital signals composed of only**ones**and

**zeros (**where a

**digital one**is represented by

**5 Volts**and an

**digital zero**is represented by

**0 Volts**). Thus, in order to work with analog signals, which in our context are basically signals that can vary from 0 to 5 V in a

*continuous way*, Sparki’s MCU has to translate them into ones and zeros. There are several techniques to do this conversion and Sparki’s MCU includes from factory an Analog to Digital Coverter (ADC). Let’s see first how it works in a generic way, so after having a basic understanding, we can deal with the specific details of our ADC. Please take a look to the following figure:

*Original image from Wikimedia Commons.*

*continuous*analog signal, while the yellow surface is the area under the curve. As our small MCU can’t do much with that curve, the ADC enters in scene, taking

**samples**of only a subset of the signal’s points (or values), and expressing each of these values with a binary number (an integer). As you may have guessed, the blue points in the previous figure are representing the sampled points. So here, a few questions appear. For example: how many samples should the ADC take in order to represent the original signal? That’s a good question, so let’s talk about it a bit more.

### ADC Sampling Rate

We are not selecting the ADC hardware here. In fact fact we*already*have the ADCs in our Sparki’s MCU. And each ADC has some specifications given by the manufacturer. So, the question about how many samples should we take, could be also asked as how many samples

*can*we take with our current ADC hardware. And the samples that our ADC can take per second is a feature called Sampling Rate. In general, higher sampling rates will let us to convert

*faster changing*analog signals. Think about it: if a signal changes a lot between 2 sample points, the ADC will loose all that intermediate information. On the other hand, if we need to store the signal’s digitized representation, more sampled points per second will result in the need of more storage space. Thus, a higher sampling rate is not always necessary. In fact, most modern ADCs has a configurable sampling rate (if you are curious about the low level details of the ADC configuration, you can take a look to the ATMega32U4 complete datasheet’s

**Analog to Digital Converter**chapter). So, to help answering our original question there is a theorem (surprised?), called Nyquist–Shannon sampling theorem. Although it’s a bit complex, the final conclusion from that theorem, in everyday language is that our sampling frequency should be

**“twice the highest frequency of interest”**. Sparki’s ADC has a maximum sampling rate of

**15 KSPS**(Kilo Samples Per Second), often called a 15 KHz sample frequency (being the KSPS a much more accurate term for describing ADC sample rates). So, make your conclusions about the maximum frequency of the signal that can be converted with this hardware.

*Although the sampling rate in theory should be higher, the specific ATMega32U4 ADC works really better with frequencies under 4 KHz, due to the way in which it’s gain stage has been designed. Happily, this is well enough for most of our needs using Sparki’s sensors.*

**A note here:**### ADC Resolution

Another important question about the conversion of a signal to the digital domain is the size of the numbers used to store each sampled point. For example, if we use just 8 bits to store a sampled value, we can represent it with only 256 different numbers. So, any point between the possible representations will be rounded to an approximate value. In the following figure, for example, we are showing an ADC technique (with 3 bits of resolution) where each sampled value (blue points) from the original signal (red curve) is mapped to a binary number below the sampled point, resulting in the blue signal. We can see clearly that the approximation is not really good with just 3 bits in this case:The quantity of bits used to store the sampled values is called the**resolution of the ADC**. As with the sample rate, a higher resolution means in general a better representation of the signal, but it also takes more memory space when storing it. And will need more processing power if we want to work mathematically with that signal. Sparki’s ADC features a

**10 bits (maximum) resolution**. This means that the analogRead function used inside the libraries for sensors like the Infrared Reflectance Sensors, or the Light Sensors can return numbers between 0 and 1023 (since 2^10 = 1024). Again, that’s good enough, as you may have seen in the previous lessons when working with Sparki’s sensors!

## Averaging Ultrasonic Range Finder Readings

Now that we have learned a few things about signal conversions, let’s start to work with real signals from the Sparki sensors. If you try the following code snippet, adapted from the Ultrasonic Ranger Finder page code, you will note that if you move your hand oscillating quickly towards and from the robot, you may see some sensor readings which are clearly false readings (with numbers like 150 cm, for example):1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <Sparki.h> // include the sparki library void setup() { } void loop() { sparki.clearLCD(); int cm = sparki.ping(); // measures the distance with Sparki's eyes sparki.print("Distance: "); sparki.print(cm); // tells the distance to the computer sparki.println(" cm"); if(cm != -1) // make sure its not too close or too far { if(cm < 10) // if the distance measured is less than 10 centimeters { sparki.beep(); // beep! } } sparki.updateLCD(); delay(50); // wait 0.1 seconds (100 milliseconds) } |

**average**. This way, instead of just printing the result of one single reading, we will take the value of 3 of them (this number is arbitrary, of course, and should be adjusted to our specific needs) and calculate the average (or arithmetic mean). This is the sum of all the read values, divided by the quantity of readings (or signal samples). Take a look to the following code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include <Sparki.h> // include the sparki library void setup() { } int average(unsigned int numberOfReadings) { float result = 0; for (unsigned int i=0; i < numberOfReadings; i++) { result += sparki.ping(); delay(20); } return result / numberOfReadings; } void loop() { float cm = average(3); // read 3 times the sensor and return the average (or arithmetic mean) sparki.clearLCD(); sparki.print("Average: "); sparki.print(cm); // tells the distance to the computer sparki.println(" cm"); if(cm != -1) // make sure its not too close or too far { if(cm < 10) // if the distance measured is less than 10 centimeters { sparki.beep(); // beep! } } sparki.updateLCD(); } |

**average**function. This function receives the desired number of sensor readings as a parameter. We defined this parameter as an

**unsigned**integer number (called

**numberOfReadings**). It’s

**unsigned**, since it does not make sense to have a negative number of readings. The core of the average function is a for cycle, which iterates “numberOfReadings” times, adding the new sensor reading value to the previous (accumulated) values:

1 2 3 4 5 6 7 8 9 10 | int average(unsigned int numberOfReadings) { float result = 0; for (unsigned int i=0; i < numberOfReadings; i++) { result += sparki.ping(); delay(20); } return result / numberOfReadings; } |

**numberOfReadings**parameter…

## A Generic Average Function

But what if we want to apply the average function to other sensors? Sparki has plenty of sensors, and calculating the arithmetic mean of their readings could be useful not just for the ultrasonic distance ranger, but for all of them. Even digital readings could be averaged (try it!). So, why not write a generic**average**function that we can use with any of these useful sensors? Let’s take a look to the following code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #include <Sparki.h> // include the sparki library float pingCallBack() { return (float)(sparki.ping()); } float accelXCallBack() { return sparki.accelX(); } float accelYCallBack() { return sparki.accelY(); } float accelZCallBack() { return sparki.accelZ(); } float average(float (*callBack)(void), unsigned int numberOfReadings, unsigned int readingsDelay) { float result = 0; for (unsigned int i=0; i < numberOfReadings; i++) { result += callBack(); if (readingsDelay) //Some sensors do not require a delay between readings, while others do. delay(readingsDelay); } return result / numberOfReadings; } void setup() { } void loop() { sparki.clearLCD(); sparki.print("Ping: "); sparki.println((int)average(pingCallBack, 2, 15)); sparki.print("Accel X: "); sparki.println(average(accelXCallBack, 30, 0)); sparki.print("Accel Y: "); sparki.println(average(accelYCallBack, 30, 0)); sparki.print("Accel Z: "); sparki.println(average(accelZCallBack, 30, 0)); sparki.updateLCD(); } |

**average**function:

1 2 3 4 5 6 7 8 9 10 11 | float average(float (*callBack)(void), unsigned int numberOfReadings, unsigned int readingsDelay) { float result = 0; for (unsigned int i=0; i < numberOfReadings; i++) { result += callBack(); if (readingsDelay) //Some sensors do not require a delay between readings, while others do. delay(readingsDelay); } return result / numberOfReadings; } |

**average**version, which was limited to work only with the ultrasonic distance ranger, this new function has some modifications which convert it into a generic function. Now, it can calculate the average of an arbitrary number of readings (the parameter

**numberOfReadings**) for any Sparky sensor. To accomplish that, we have introduced two changes to the code. The first is quite simple: the fixed delay was changed by a variable delay, adding a new parameter called

**readingsDelay**. This way, the previous

**delay(20)**is now the following line:

1 2 | if (readingsDelay) //Some sensors do not require a delay between readings, while others do. delay(readingsDelay); |

**if statement**there, so if

**readingsDelay**has a value of zero, the

**delay()**function is not even called).The second change is a bit more complex, but easy to understand too. As you can see in the code, the call to the

**sparki.ping()**function was replaced by a call to something called

**callBack()**. So, what’s this? A callback function is a function that we can pass as a parameter to another function, making it possible for this last one to call it. This enables the function to call different (callback) functions in different situations.The basic idea here is that we define new functions to read sensors, and then we pass the function for each sensor to our

**average**function as a parameter, as you can see in our code’s

**loop**:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void loop() { sparki.clearLCD(); sparki.print("Ping: "); sparki.println((int)average(pingCallBack, 2, 15)); sparki.print("Accel X: "); sparki.println(average(accelXCallBack, 30, 0)); sparki.print("Accel Y: "); sparki.println(average(accelYCallBack, 30, 0)); sparki.print("Accel Z: "); sparki.println(average(accelZCallBack, 30, 0)); sparki.updateLCD(); } |

**average**is called first with

**pingCallBack**as its first parameter, then with

**accelXCallBack**, and so on. But if you take a look to the definitions of

**pingCallBack**and the other functions, they are just standard functions with nothing special, except for the fact that all of them has the same signature, which just means that they return the same kind of thing (a float in our case) and receives exactly the same kind of parameters (nothing in our functions):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | float pingCallBack() { return (float)(sparki.ping()); } float accelXCallBack() { return sparki.accelX(); } float accelYCallBack() { return sparki.accelY(); } float accelZCallBack() { return sparki.accelZ(); } |

**average**function, the first parameter just specifies the format of the functions that

**average**is expecting to receive:

1 | float average(float (*callBack)(void), unsigned int numberOfReadings, unsigned int readingsDelay) |

**float**is the return type, and

**(*callBack)**is the name to be used inside the

**average**function when we call it. Please take into account that it may be any valid C/C++ function name and we just used callBack because it liked to us, nothing else. But it’s important to enclose it with parenthesis and to add the “*” before the name, to indicate that we are passing a pointer to a function (please don’t worry if you don’t understand the pointer concept right now, since it’s not really important to understand this lesson). Finally, the “

**(void)**” construction there indicates that the callback function itself will not receive parameters. Again, the parenthesis there are important. Inside

**average,**the callback function will be called by it’s name, just as any other function call. In our case, se add the result returned by

**callBack()**to the

**result**variable:

1 | result += callBack(); |