LEGO EV3 Pendulum
Lesson Objectives:
Materials:
Lesson Objectives:
- Students will use programming to measure and analyze a physical system
- Students will learn to perform peak finding
- Students will learn to write data to files
Materials:
- EV3 MicroPython Documentation
- LEGO EV3 Brick
- 1 gyro sensor
- Micro SD card with EV3 MicroPython image
- Laptop with Visual Studio Code
- LEGO® MINDSTORMS® EV3 MicroPython Extension
- Assorted LEGO pieces to construct a pendulum
Goal:
Use an EV3 and gyro sensor to create a data logger that measures the motion and calculates the period of a LEGO pendulum.
Use an EV3 and gyro sensor to create a data logger that measures the motion and calculates the period of a LEGO pendulum.
Construction:
Use LEGO pieces to construct a pendulum. You should make it easy to adjust the length, so data can be collected for different lengths. The EV3 and gyro should attach to the bottom of the pendulum and the gyro should be oriented so that it detects when the pendulum swings. An example image is shown below.
Use LEGO pieces to construct a pendulum. You should make it easy to adjust the length, so data can be collected for different lengths. The EV3 and gyro should attach to the bottom of the pendulum and the gyro should be oriented so that it detects when the pendulum swings. An example image is shown below.
Basic Data Logger:
Create a EV3 program to log gyro sensor data to a text file. You also want to log the time each reading occurs at. Time can be calculated using the StopWatch feature on the EV3.
Create a EV3 program to log gyro sensor data to a text file. You also want to log the time each reading occurs at. Time can be calculated using the StopWatch feature on the EV3.
measuring time with the ev3
MicroPython for EV3 has a StopWatch class which you can use to measure elapsed time since a certain point. Classes are a more advanced topic that we will not discuss in depth, but the important thing is before we can use the functions in the class we need to create an object. This is the same as intializing motors and sensors. We can then call the functions in the class using dot notation with the object, similar to in modules.
The time() function gets the current time since the stopwatch started. When we initialize the object s, it also starts the timer from 0.
Think about how you want the user to interact with the logger. How does the user start and stop collecting data? How does the user know it is working properly? How much processing of the data is done in real time on the micro:bit vs later on your computer?
You should aim to collect data at least 10 Hz, though faster is better. Do not artificially slow down your code if it is faster than 10 Hz.
Take a look at tutorials on file input and output here and here.
You should aim to collect data at least 10 Hz, though faster is better. Do not artificially slow down your code if it is faster than 10 Hz.
Take a look at tutorials on file input and output here and here.
Take a look at the sample code below. Make sure you understand both your own code and the sample before continuing because everything will build on this base structure. Also, make a copy of your code before modifying it in the next step.
Basic Logger code
Instructions for Data Logger
- Flash this program onto the EV3
- Thumbs Up should appear on screen
- Disconnect EV3 from computer and attach to pendulum
- Make sure pendulum is in down position and motionless
- Press center button to begin logging data
- After a 1 second delay, gyro will calibrate to 0 (It is import it is not moving for this)
- EV3 will display Eyes and begin logging
- Start pendulum swinging
- Press center button again to stop logging data
- A Stop Sign should appear on the screen
- Reconnect to computer and open VS Code
- Download 'gyro_data.txt' to your computer
- When you open the file, you should see it filled with data.
Period Calculation:
One thing we may want to measure is the period of the pendulum.
One thing we may want to measure is the period of the pendulum.
Understanding Period
As you may or may not know, the period of a pendulum has the following relationship:
.Where T is period, L is the length of the pendulum, and g is the gravitational constant (9.81 m/s^2). So if we can measure the period of a pendulum we can determine the length (assuming we are on Earth). Conversely we can calculate an expected period based on the length and compare that to the measured value.
If you run the data logger you wrote and plot the angle of the gyroscope, you will see that it is sinusoidal. One oscillation is one stroke back and forth of the pendulum and the time that oscillation takes is the period.
If you run the data logger you wrote and plot the angle of the gyroscope, you will see that it is sinusoidal. One oscillation is one stroke back and forth of the pendulum and the time that oscillation takes is the period.
We can determine the period by measuring the time between like-points in the pendulum's oscillation. Probably the simplest point to measure is when the angle reaches a local maximum. In order to do this we need to find what is called a peak.
In the most basic sense, a data point is a peak if it is greater than both the point before it and the point after it. For the function y = -x^2, there is a peak at x = 0, because both the values for x < 0 and for x > 0 are less than the value at x = 0.
In the most basic sense, a data point is a peak if it is greater than both the point before it and the point after it. For the function y = -x^2, there is a peak at x = 0, because both the values for x < 0 and for x > 0 are less than the value at x = 0.
Algorithm:
The algorithm we are about to implement is based off the SciPy find_peaks() function. You may find this helpful to read, but we are not going to implement it exactly.
Before continuing, make sure to make a copy of your code.
Let's make a function called find_peak that takes a list of 3 consecutive gyro readings as an input and returns a boolean True if the middle element is a peak and False if it is not. The element is a peak if it is greater than both of the of the other elements. Implement this conditional in the function and put the function at the top of your data logger code.
The overall structure of our algorithm is:
The trickiest part of this is that we need to know what comes after the point we are looking at to determine if it is a peak or not. In order to do this we need to collect the next data point before checking if the current one is a peak. This is why the point we are checking in find_peak is the middle element of the list. The process for this looks like:
There are a few other things that need to be added to your program:
At this point the program should theoretically work. However, if the EV3 repeats the same measurement consecutively a lot, you may end up with an empty file. There are two quick ways to fix this for now, but we will improve on this in the next step.
You should now have at least something in your results file, though the periods will likely be way smaller than expected. You may find it useful for debugging to write more things to the data file.
The algorithm we are about to implement is based off the SciPy find_peaks() function. You may find this helpful to read, but we are not going to implement it exactly.
Before continuing, make sure to make a copy of your code.
Let's make a function called find_peak that takes a list of 3 consecutive gyro readings as an input and returns a boolean True if the middle element is a peak and False if it is not. The element is a peak if it is greater than both of the of the other elements. Implement this conditional in the function and put the function at the top of your data logger code.
The overall structure of our algorithm is:
- Read in an angle value and record the corresponding time
- Determine if that data point represents a peak
- If it is, calculate the period of the oscillation that just ended and write the period to a file. Additionally, feel free to make the EV3 beep, to provide real-time feedback.
The trickiest part of this is that we need to know what comes after the point we are looking at to determine if it is a peak or not. In order to do this we need to collect the next data point before checking if the current one is a peak. This is why the point we are checking in find_peak is the middle element of the list. The process for this looks like:
- Add a new value to the end of the list (append)
- Call find_peak on the list
- Remove the first element from the list (pop)
- Repeat
There are a few other things that need to be added to your program:
- Collect several data points before we start calling find_peaks, so the list is the right length.
- Period calculation
- File output
At this point the program should theoretically work. However, if the EV3 repeats the same measurement consecutively a lot, you may end up with an empty file. There are two quick ways to fix this for now, but we will improve on this in the next step.
- Add a wait between each measurement, so the pendulum has time to move further (Try between 10 and 100 milliseconds)
- Change the conditional in find_peak from greater than to greater than or equal
You should now have at least something in your results file, though the periods will likely be way smaller than expected. You may find it useful for debugging to write more things to the data file.
Logger with Simple Peak Finding
Complex Peak Finding:
Now that we have the basic structure of the code working, let's think about ways to improve the results. Take a look at some of the optional parameters of the SciPy find_peaks() function. Let's try to implement some of those concepts.
Before continuing, make sure to make a copy of your code.
Global Variables:
To make it easy to test different values for the parameters and to follow good coding style, make each parameter a global variable. Global variables can be accessed from any part of your program, so they are good for things like mathematical constants that are used in a lot of places in your code, but not modified much. Be careful with them, as they can cause unexpected issues when multiple parts of your code modify their values. Global variables go at the top of your code, just below the import statements, and are commonly given names in ALL CAPS.
Parameters:
Some parameters you may want to try implementing include:
Additionally, as discussed in the last step, you likely will want to change the greater than in the find_peaks function to greater than or equal to. Otherwise, you may miss peaks, as consecutive values tend to repeat a lot.
Implement these parameters and then test different values to see what gives you the best results. There is no perfect answer, but the values that worked well for the sample setup are at the top of the code below.
Your data file should contain mostly consistent measurements of the period (Ignore the first and last values as the EV3 was only recording for part of those oscillations). Time your pendulum with a stop watch and see how it compares to the EV3's measurements.
Now that we have the basic structure of the code working, let's think about ways to improve the results. Take a look at some of the optional parameters of the SciPy find_peaks() function. Let's try to implement some of those concepts.
Before continuing, make sure to make a copy of your code.
Global Variables:
To make it easy to test different values for the parameters and to follow good coding style, make each parameter a global variable. Global variables can be accessed from any part of your program, so they are good for things like mathematical constants that are used in a lot of places in your code, but not modified much. Be careful with them, as they can cause unexpected issues when multiple parts of your code modify their values. Global variables go at the top of your code, just below the import statements, and are commonly given names in ALL CAPS.
Parameters:
Some parameters you may want to try implementing include:
- SLEEP_TIME - Time to pause between measurements (see above)
- WINDOW - Instead of just looking at 1 measurement on each side of possible peak, try looking at a larger window. If the point is not larger than all others in the window, it is not a peak. This should reduce the false positive rate.
- MIN_DISTANCE - Minimum number of measurements since the last peak until a new measurement can be considered a peak. You likely can assume the period of the pendulum you are testing is on the order of seconds, so if you detect 2 peaks in a small fraction of a second, you know something is wrong.
- MIN_HEIGHT - Minimum data value to be considered a peak. If you test your sensor and know roughly how large you can expect the value of peaks to be, you can ignore everything significantly below that value.
Additionally, as discussed in the last step, you likely will want to change the greater than in the find_peaks function to greater than or equal to. Otherwise, you may miss peaks, as consecutive values tend to repeat a lot.
Implement these parameters and then test different values to see what gives you the best results. There is no perfect answer, but the values that worked well for the sample setup are at the top of the code below.
Your data file should contain mostly consistent measurements of the period (Ignore the first and last values as the EV3 was only recording for part of those oscillations). Time your pendulum with a stop watch and see how it compares to the EV3's measurements.
Logger with Complex peak finding