Doing an experiment with the BMP085 pressure-temperature-altitude sensor

 Let's put together the reading of the BMP085 sensor and the writing of data to the SD card. We'll start from an Arduino program shown below that has already put the two pieces together. Upload this program to the Arduino and check that it is saving data to the SD card.


To make sure you have some understanding of the program, see if you can

  • Change the filename that is saved to "your initials.csv". The .csv will be recognized by Microsoft Excel for easy opening and analysis.
  • Add column headings to the file that are pressure, temperature, altitude
  • Add a delay so that it records data every 5 seconds.
  • Determine the units of each measurement (PTH).

Next, go outside and determine a method for estimating the height of the building. Write a procedure for this estimate that is clear such that someone else could use the procedure and repeat your estimation.

Now, add a breadboard power supply. The power actually comes from a 9 volt battery that connects to this, which regulates the power to be appropriate for the Arduino.

5V and 3.3V breadboard power supply.

With everything connected walk up the stairs from the first floor to the top floor and back to the lab. Remove the SD card and save your data to the computer in the lab. In Excel, determine how high the top floor is. How does it compare to your estimation? Your data should look something like the graph below if you plot it.

Altitude vs. time of walking from basement to observatory in the Berea Science Building.

Come up with a method for determining the uncertainty of your estimate. Does this uncertainty give agreement between your estimation and the measurement. Explain in some detail how this process could be improved to get better agreement.

Measuring Pressure, Temperature, and Altitude

 This is a big one! The Arduino is going to do some heavy lifting for us. We are going to program a pressure, temperature, and altitude sensor (all-in-one). We'll check that it works. Then, we'll program an SD card adapter and make sure we can send data to a file on the SD card. Finally, we'll put the two together and power the Arduino with a battery so we can do some portable data collection.

The PTH (pressure, temperature, height) sensor is the Adafruit BMP180. It is shown below. It communicates through a protocol called I2C (Inter-Integrated Circuit). While it is good to understand these protocols, we can get away with knowing almost nothing since libraries have already been written to work with this sensor. To begin, in Arduino open from the sketchbook a program called BMP085 (see below). We'll go over the code together in lab and see that we know how to identify key features for getting data from the sensor.

The BMP180 pressure/temperature/altitude sensor from Adafruit.


To wire the sensor, look at the diagram below. Make sure your Arduino is NOT connected to the computer while wiring the sensor. Let the TA or instructor verify your connections before connecting the Arduino to the computer through USB.

Connections of the BMP180 to the Arduino.


Upload the code to the Arduino and use the Serial Monitor to read the sensor output. Does it appear to work as you would expect? How might you test it for altitude? e.g., what is the altitude of Berea, KY above sea level? How might you test it for temperature? Try it.

Before we move on to the SD card, let's make sure we know how to create some data that looks like something we know. Open a new Arduino sketch and save it as SineWave-yourinitials. We'll write a program to create a sine function \(y=\sin\omega t\). First, we need to declare some variables to store the time and the y value. Note that in Arduino, "time" is a protected keyword, and we cannot use it to store the time. Both of these values need to be decimal numbers. In Arduino, this is declared as "float".

float ts=0, yt;
void setup(){ 
... 
}
We want to start the time at zero seconds. So it is initialized above. I call it "ts" for time in seconds. I call the function value "yt" for y as a function of t. Notice this declaration is before the setup, making these variables global to the entire program. In the loop we want to get the value of time using the millis() function. Convert this to seconds by dividing it by 1000.0. Once we have the time we can calculate the sine value. In Arduino "sin" is a known function and expects radians in its argument.
yt = sin(6.28*ts);

Finally, we need to write these values to the serial port. This requires beginning serial communication in the setup.

Serial.begin(9600);

Then, it requires writing the values to the serial port in the loop after they have been calculated.

Serial.print(ts);
Serial.print(", ");
Serial.println(yt);

Test that this works by uploading it to the Arduino and seeing what happens in the Serial Monitor. Copy and past some of the data into Excel and make a graph of it. Does it look like you expect?

Now that the sensor is working and we know how to create known data, let's try to save information to an SD card. We are going to use the Catalex MicroSD Card Adapter. An pin diagram is shown below.

This device communicates through what is called SPI (Serial Peripheral Interface). Similarly, we don't have to know exactly how this works at this point as long as we can use existing libraries. Wire the adapter as described. NOTE: The pins on your adapter are not in the same order as the image shown below. Read the connection table in the figure below. Disconnect your Arduino before making connections. Let a TA or instructor see your connections before powering the Arduino with the USB cable.
Wire connections for the SD Card adapter.


In the Arduino software, open the sketch SD_card_write (see below). We will discuss features of the program together in lab. Afterward, see if you can create a way to store the values of \(\sin \omega t\) where \(\omega = 2\pi\) and time is calculated using the Arduino function "millis()". Store the value in decimal variable (float) and write the time and sine wave values to a file on the SD card. Make the filename "sinewavedata.txt". Remove the SD card and use Excel to plot the data in the file.

Measuring the acceleration of a fan cart

 Let's look at some more complex motion with our motion sensor. We will measure the motion of a cart driven by a fan. The arrangement is shown below.

Fan Cart Setup
We are going to add one more level of complexity to our measurement. We want to get an accurate time measurement instead of assuming the time increases by the delay time. To do this we will use a function called "millis" on the Arduino. We can keep track of time and position by reporting both to the serial port using something like the following lines of code.
Serial.print(millis()*1000);
Serial.print(",");
Serial.println(distance);

In this example, the first line of code prints the time in milliseconds multiplied by 1000 to convert to seconds. This line will not put a carriage return since it has

print
rather than
println
The second line prints a comma, and the third line prints the distance with a carriage return. The distance should be your calibrated distance from previous lab work. The third line will insert a carriage return so that the next values that go to the serial port are on a new line.

Now we are ready to measure the motion. Place the cart on the track so that it moves away from the motion sensor.  Using the switch on the Arduino, start the cart moving by turning on the fan and measure the motion of the cart while it is moving freely between the track ends. Be sure the Serial Monitor is open so you can copy the time and position data after the measurement ends.

Copy and paste the data into Microsoft Excel. Make a graph of the data (be sure to label the graph axes). Add a polynomial trendline to the graph, and use it to determine the initial position, initial velocity, and acceleration. Recall \( x_f = x_i +v_i t + \frac{1}{2}at^2 \)is related to the trendline \( y=c+bx+ax^2 \)

Fan Cart Data


Have the cart move toward the motion sensor to determine whether the acceleration is the same magnitude but opposite direction. If you feel like the measurement of acceleration is reproducible, try adding mass to the cart and measuring the acceleration again. Repeat this for one more addition of mass.  Be sure to keep the mass in the middle of the cart so that it doesn't have more mass on one side of it.

When you have three masses measured, make a graph in Excel of acceleration (y-axis) vs. mass (x-axis). How do the two values appear to be related (linear, quadratic, hyperbolic)? Try adding a "power law" trendline to determine the dependence. Sir Isaac Newton said that force is mass times acceleration. \( F=ma \). Assuming the fan exerts a constant force because it always blows air in the same way, we can assume the force is some constant number. Rearranging the equation \( a=F/m \). Does this agree with your graph trendline? Explain. What is the force the fan exerts?

Adding a switch to Arduino data collection

Once an Arduino measurement system is reporting measurements such as distance described in the previous post, it's nice to add the capability to turn the data reporting on and off. This is because the Arduino continuously loops, making it difficult to extract "real" data from the stream of values being reported. One could add a delay to slow the reporting, but this will affect measurements like motion by limiting the range precision of position measurements and thus reducing the range of velocities that are measureable.

Let's look at having the Arduino report measurements only when a switch is "on". This is going to require us to understand the idea of digital input and output (I/O), which is different than the analog input we measure with the ultrasonic sensor.

A switch is added to our distance sensor setup. It is connected to three digital pins 4, 5, and 6.
A circuit can be constructed as shown above, where three digital pins (4, 5,6) from the Arduino are connected to the poles of a switch. The two outer digital pins (4 and 6) will be set to output particular values. Pin 4 will be digital HIGH or 1, and pin 6 will be digital LOW or 0. The center pole is connected to pin 5, which will be an input value we read. When the switch is left, it connects the middle input pin 5 to pin 6. In this case we read LOW or 0. We will equate this to "off", and will not report measurements to the Serial port. When the switch is right, it connects the middle input pin 5 to pin 4. In this case we read HIGH or 1. We will equate this to "off", and will report measurements to the Serial port. The conditional reporting of data is accomplished using an if-then-else statement as shown. We will first look at code for the switch only. Then, we will insert our distance sensor code appropriately.
  
 //This program will set digital pins 4 and 6 to HIGH and LOW.
 //It will also read the digital pin 5.
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); //open communication b/w the Arduino and computer
  pinMode(4, OUTPUT);//set digital pin 4 as output
  pinMode(5, INPUT);//set digital pin 5 as input
  pinMode(6, OUTPUT);//set digital pin 6 as output
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(4, HIGH);
  digitalWrite(6, LOW);
  if(digitalRead(5) == HIGH){
    //check to see if the switch is "on"
    Serial.println("report data");//if "on" send to the serial port 
  }
  else{
    //if the switch is "off" 
    //do nothing and move on 
  }
  delay(200);
}
  
Compile and upload this code to your Arduino. Using the Serial Monitor, check that the switch functions properly. Once it is functioning properly, see if you can modify the program to include the distance sensor reading from our last lab. Don't forget there is a variable declaration at the beginning of the distance sensor program. The reading and reporting of the sensor should only occur if the switch is on.

Recompile and upload your code to check the functioning of your code. If it appears to work, test it in various conditions. For example, try to measure an object such as a ball rolling across the table. Use tape on the table to turn the switch on and off to capture the motion only while the ball is moving between the initial and final tape points.

Let's look at constant velocity motion with our sensors.

  1. Look at the following graphs. You will be given printed copies of them. Label on the graphs each section corresponding to motion that is different from the section before and after. In the label, include the \(\Delta x, \Delta t\), and average velocity, \(\langle v\rangle\). Also, write one sentence explaining what happens in that section of motion, e.g., “The object undergoes a displacement in the positive direction of 2 meters over 1 second, giving a velocity of 2 m/s in the positive direction.”

    Graph 1 of position vs. time.

    Graph 2 of position vs. time.

    Graph 3 of position vs. time.

  2. Use your motion sensor and Arduino to create duplicate graphs like these by moving in front of the sensor with a small whiteboard. You should be careful to produce the graphs as accurately as possible including the particular distances and times. Putting tape on the floor may help. Practice with the Serial Plotter, then use the Serial Monitor to collect data that you copy and paste into Excel. For the time variable, assume each data point corresponds to the delay of 100 ms. This is not quite right since the Arduino takes time to loop, but it is off by less than 1 ms.
  3. In Excel make graphs of your motion to include in a lab report.
  4. Expectations: The velocities are to be calculated correctly. Experimentally, the average velocity within each time segment of your LoggerPro graph should be within 1 m/s of the calculated value. Be sure to calculate these for each segment. Also the starting/ending times of each time segment of your LoggerPro graph should be within 1 second of those given in the position vs time graphs.
  5. Lab Report

    Write a summary report in Microsoft Word. You will save it to the shared OneDrive that I sent a link. Makes sure the relevant Excel work is in the Word document. I do not want your Excel document. In your lab report include:

    1. The three questions from last week.
    2. Do the answers to these questions affect the precision of today's measurements?
    3. The labeled handout graphs. Take a picture of them with a webcam or phone.
    4. Your Excel graphs and calculations of average velocity for each segment. Be clear about how you calculate average velocities by including \(x_i, x_f, t_i, t_f\).
    5. Describe the motion sensor's coordinate system. How does it define positive and negative?

Motion Sensors and Arduino

We are using the MaxSonar-EZ1 ultrasonic rangefinder. It will be connected to an Arduino (the Metro Mini by Adafruit). Setting up the sensor is very simple since the rangefinder only needs 5 volts and ground for power. The output indicating the distance an object is from the sensor can be obtained in a variety of ways. Here we use the analog signal marked

"AN". The connections look like this.
Arduino Metro Mini with a MaxSonar EZ1 connected.


The sensor continuously sends sonic pulses once the power connections are made to an Arduino that is powered. If you put your ear close to it, you can hear the ticking of the pulses. Although the sensor has three ways to measure a signal, the analog voltage output seems to be the most straightforward to use. The analog output is a voltage between 0 and 5 volts that is proportional to the distance an object is from the sensor. However, the Arduino reports this value as an integer between 0 and 1023. That is, 5 volts is reported as 1023 and 0 volts is reported as 0. Can you determine what value 2.5 volts is reported?

Once connected, we need to write a program to read the sensor and report the reading back to the computer. The code that is shown reads analog pin number 0 (A0) and stores the read value in a variable named ultrasonic_voltage. The value of ultrasonic_voltage is then written to the serial port and can be viewed by opening the Serial Monitor.

//This is a comment that does not affect the program.
//This program will read the analog 0 (A0) pin on an Arduino and report the value to the computer USB
int ultrasonic_voltage;//This is an integer variable that stores the analog reading
void setup() {
    // put your setup code here, to run once:
    Serial.begin(9600); //open communication between the Arduino and the computer
}

void loop() {
    // put your main code here, to run repeatedly:
    ultrasonic_voltage = analogRead(A0); 
    //put the calibration equation here once you have it
    Serial.println(ultrasonic_voltage); //write to the USB
}
Several things to know about Arduino. The programming is strict. Be careful about semicolons (;), curly brackets ({}), and comments (//).  The highlighting shows you in many cases when you have used something recognizable such as "Serial" or "analogRead". The Arduino can loop quickly. The actual speed depends on how big your program is. Generally speaking it can complete a loop in microseconds. Therefore, one may want to insert a delay of a few hundred milliseconds while calibrating the sensor. Anytime you make a change to the program, it needs to be recompiled and uploaded to the Arduino.

Now, let's calibrate the sensor by holding a large object such as a spiral notebook or dry erase board in front of the sensor. Using a meter stick, collect approximately 10 ultrasonic_voltages and corresponding meter stick distances. Put these values in Excel, and graph them.

Ultrasonic Voltage Distance (m)
16 0.2
50 0.9
125 1.75
175 2.3
200 2.9
250 3.5
300 4.1
350 4.6
375 5.2
450 6.1
512 7.0

Add a trendline to your graph of distance (m) vs. ultrasonic_voltage. See the example below.
Graph of the distance an object is from an ultrasonic rangefinder vs. the ultrasonic sensor reading. The trendline is a calibration curve.

The trendline should be linear. Be sure to show the equation and R2 value. We now want to add this trendline to the Arduino code so that the serial port output is calibrated to real distance. To do this, a new variable should be created similar to

int ultrasonic_voltage;

However, we want the new variable to be capable of storing decimal numbers so it can report values down to 0.001 m (1 mm). To do this create a floating point variable on the line after the one shown above.

float distance;

In the Arduino program insert the trendline equation after the line with analogRead. Be sure to substitute the variable names "ultrasonic_voltage" and "distance" for x and y appropriately. And don't forget a semicolon at the end of the line. Finally, change the variable that is printed to the serial port to be distance. Recompile and upload this program. Test your calibration by repeating some measurements.

Questions to address:

  1. Is there a minimum and maximum distance that can be measured?
  2. Is there a minimum change in distance that can be measured?
  3. Does the minimum change that can be measured change with distance from the sensor?

Use the answers to these questions to summarize the capabilities of your sensor to measure distances. Use the ideas of absolute and relative uncertainty that we discussed in class.