Hi guys, welcome to today’s post. One of the most fascinating thing about being a maker is knowing how to develop makeshift tools, you will never get stuck working on any project when you have that kind of versatility. So Today, I will be sharing how to build a Raspberry Pi based makeshift version of one of the most important tools in Electrical/Electronics engineering; The Oscilloscope.
The oscilloscope is an electronic test instrument that allows the visualization and observation of varying signal voltages, usually as a two dimensional plot with one or more signals plotted against time. Today’s project will seek to replicate the signal visualization capabilities of the oscilloscope using the Raspberry Pi and an analog to digital converter module.
Project Flow:
Replicating the signal visualization of the oscilloscope using the Raspberry Pi will require the following steps;
1. Perform Digital to analog conversion of the Input signal
2. Prepare the resulting data for representation
3. Plot the data on a live time graph
A simplified block diagram for this project would look like the diagram below.
Project Requirements
The requirement for this project can be classified into two:
- Hardware Requirements
- Software Requirements
Hardware requirements
To build this project, the following components/part are required;
- Raspberry pi 2 (or any other model)
- 8 or 16GB SD Card
- LAN/Ethernet Cable
- Power Supply or USB cable
- ADS1115 ADC
- LDR (Optional as its meant for test)
- 10k or 1k resistor
- Jumper wires
- Breadboard
- Monitor or any other way of seeing the pi’s Desktop(VNC inclusive)
Software Requirements
The software requirements for this project are basically the python modules (matplotlib and drawnow) that will be used for data visualization and the Adafruit module for interfacing with the ADS1115 ADC chip. I will show how to install these modules on the Raspberry Pi as we proceed.
While this tutorial will work irrespective of the raspberry pi OS used, I will be using the Raspberry Pi stretch OS and I will assume you are familiar with setting up the Raspberry Pi with the Raspbian stretch OS, and you know how to SSH into the raspberry pi using a terminal software like putty. If you have issues with any of this, there are tons of Raspberry Pi Tutorials on this website that can help.
With all the hardware components in place, let's create the schematics and connect the components together.
Circuit Diagram:
To convert the analog input signals to digital signals which can be visualized with the Raspberry Pi, we will be using the ADS1115 ADC chip. This chip becomes important because the Raspberry Pi, unlike Arduino and most micro-controllers, does not have an on-board analog to digital converter(ADC). While we could have used any raspberry pi compatible ADC chip, I prefer this chip due to its high resolution(16bits) and its well documented datasheet and use instructions by Adafruit. You can also check our Raspberry Pi ADC tutorial to learn more about it.
The ADC is an I2C based device and should be connected to the Raspberry Pi as shown in the schematics below.
For clarity, the pin connection between the two components is also described below.
ADS1115 and Raspberry Pi Connections:
VDD – 3.3v
GND – GND
SDA – SDA
SCL – SCL
With the connections all done, power up your pi and proceed to install the dependencies mentioned below.
Install Dependencies for Raspberry Pi Oscilloscope:
Before we start writing the python script to pull data from the ADC and plot it on a live graph, we need to enable the I2C communication interface of the raspberry pi and install the software requirements that were mentioned earlier. This will be done in below steps so its easy to follow:
Step 1: Enable Raspberry Pi I2C interface
To enable the I2C, from the terminal, run;
sudo raspi-config
When the configuration panels open, select interface options, select I2C and click enable.
Step 2: Update the Raspberry pi
The first thing I do before starting any project is updating the Pi. Through this, I am sure every thing on the OS is up to date and I won’t experience compatibility issue with any latest software I choose to install on the Pi. To do this, run below two commands:
sudo apt-get update sudo apt-get upgrade
Step 3: Install the Adafruit ADS1115 library for ADC
With the update done, we are now ready to install the dependencies starting with the Adafruit python module for the ADS115 chip. Ensure you are in the Raspberry Pi home directory by running;
cd ~
then install the build-essentials by running;
sudo apt-get install build-essential python-dev python-smbus git
Next, clone the Adafruit git folder for the library by running;
git clone https://github.com/adafruit/Adafruit_Python_ADS1x15.git
Change into the cloned file’s directory and run the setup file;
cd Adafruit_Python_ADS1x1z sudo python setup.py install
After installation, your screen should look like the image below.
Step 4: Test the library and 12C communication.
Before we proceed with the rest of the project, it is important to test the library and ensure the ADC can communicate with the raspberry pi over I2C. To do this we will use an example script that comes with the library.
While still in the Adafruit_Python_ADS1x15 folder, change directory to the examples directory by running;
cd examples
Next, run the sampletest.py example which displays the value of the four channels on the ADC in a tabular form.
Run the example using:
python simpletest.py
If the I2C module is enabled and connections good, you should see the data as shown in the image below.
If an error occurs, check to ensure the ADC is well connected to the PI and I2C communication is enabled on the Pi.
Step 5: Install Matplotlib
To visualize the data we need to install the matplotlib module which is used to plot all kind of graphs in python. This can be done by running;
sudo apt-get install python-matplotlib
You should see an outcome like the image below.
Step6: Install the Drawnow python module
Lastly, we need to install the drawnow python module. This module helps us provide live updates to the data plot.
We will be installing drawnow via the python package installer; pip, so we need to ensure it is installed. This can be done by running;
sudo apt-get install python-pip
We can then use pip to install the drawnow package by running:
sudo pip install drawnow
You should get an outcome like the image below after running it.
With all the dependencies installed, we are now ready to write the code.
Python Code for Raspberry Pi Oscilloscope:
The python code for this Pi Oscilloscope is fairly simple especially if you are familiar with the python matplotlib module. Before showing us the whole code, I will try to break it into part and explain what each part of the code is doing so you can have enough knowledge to extend the code to do more stuffs.
At this stage it is important to switch to a monitor or use the VNC viewer, anything through which you can see your Raspberry Pi’s desktop, as the graph being plotted won’t show on the terminal.
With the monitor as the interface open a new python file. You can call it any name you want, but I will call it scope.py.
sudo nano scope.py
With the file created, the first thing we do is import the modules we will be using;
import time import matplotlib.pyplot as plt from drawnow import * import Adafruit_ADS1x15
Next, we create an instance of the ADS1x15 library specifying the ADS1115 ADC
adc = Adafruit_ADS1x15.ADS1115()
Next, we set the gain of the ADC. There are different ranges of gain and should be chosen based on the voltage you are expecting at the input of the ADC. For this tutorial, we are estimating a 0 – 4.09v so we will be using a gain of 1. For more info on gain you can check the ADS1015/ADS1115 datasheet.
GAIN = 1
Next, we need to create the array variables that will be used to store the data to be plotted and another one to serve as count.
Val = [ ] cnt = 0
Next, we make know our intentions of making the plot interactive known so as to enable us plot the data live.
plt.ion()
Next, we start continuous ADC conversion specifying the ADC channel, in this case, channel 0 and we also specify the gain.
It should be noted that all the four ADC channels on the ADS1115 can be read at the same time, but 1 channel is enough for this demonstration.
adc.start_adc(0, gain=GAIN)
Next we create a function def makeFig, to create and set the attributes of the graph which will hold our live plot. We first of all set the limits of the y-axis using ylim, after which we input the title of the plot, and the label name before we specify the data that will be plotted and its plot style and color using plt.plot(). We can also state the channel (as channel 0 was stated) so we can identify each signal when the four channels of the ADC are being used. plt.legend is used to specify where we want the information about that signal(e.g Channel 0) displayed on the figure.
plt.ylim(-5000,5000) plt.title('Osciloscope') plt.grid(True) plt.ylabel('ADC outputs') plt.plot(val, 'ro-', label='lux') plt.legend(loc='lower right')
Next we write the while loop which will be used constantly read data from the ADC and update the plot accordingly.
The first thing we do is read the ADC conversion value
value = adc.get_last_result()
Next we print the value on the terminal just to give us another way of confirming the plotted data. We wait a few seconds after printing then we append the data to the list (val) created to store the data for that channel.
print('Channel 0: {0}'.format(value)) time.sleep(0.5) val.append(int(value))
We then call drawnow to update the plot.
drawnow(makeFig)
To ensure the latest data is what is available on the plot, we delete the data at index 0 after every 50 data counts.
cnt = cnt+1 if(cnt>50): val.pop(0)
That’s all!
The complete Python code is given at the end of this tutorial.
Raspberry Pi Oscilloscope in Action:
Copy the complete python code and paste in the python file we created earlier, remember we will need a monitor to view the plot so all of this should be done by either VNC or with a connected monitor or screen.
Save the code and run using;
sudo python scope.py
If you used a different name other than scope.py, don’t forget to change this to match.
After a few minutes, you should see the ADC data being printed on the terminal. Occasionally you may get a warning from matplotlib (as shown in the image below) which should be suppressed but it doesn’t affect the data being displayed or the plot in anyway. To suppress the warning however, the following lines of code can be added after the import lines in our code.
Import warnings import matplotlib.cbook warnings.filterwarnings(“ignore”, category=matplotlib.cbook.mplDeprecation)
That’s it for this tutorial guys, to fully test your oscilloscope, you can connect an analog device like a potentiometer to a channel on the ADC and you should see the data change with each turn of the potentiometer. Or you can input Sine wave or square wave to test the output.
Thanks for reading, if you have any question(s) or something you will like me to add, just leave me a comment.
Till next time, Keep making!
import time
import matplotlib.pyplot as plt
#import numpy
from drawnow import *
# Import the ADS1x15 module.
import Adafruit_ADS1x15
# Create an ADS1115 ADC (16-bit) instance.
adc = Adafruit_ADS1x15.ADS1115()
GAIN = 1
val = [ ]
cnt = 0
plt.ion()
# Start continuous ADC conversions on channel 0 using the previous gain value.
adc.start_adc(0, gain=GAIN)
print('Reading ADS1x15 channel 0')
#create the figure function
def makeFig():
plt.ylim(-5000,5000)
plt.title('Osciloscope')
plt.grid(True)
plt.ylabel('ADC outputs')
plt.plot(val, 'ro-', label='Channel 0')
plt.legend(loc='lower right')
while (True):
# Read the last ADC conversion value and print it out.
value = adc.get_last_result()
print('Channel 0: {0}'.format(value))
# Sleep for half a second.
time.sleep(0.5)
val.append(int(value))
drawnow(makeFig)
plt.pause(.000001)
cnt = cnt+1
if(cnt>50):
val.pop(0)
Comments
Thanks for this.
Thanks so much for this bro, you never cease to inspire me. Well done
What is the baud rate you are
What is the baud rate you are operating it at and what is the maximum frequency you have been able to observe properly?
Time change
How do I make the scope work in real-time. It seems to lag a good bit. I am using the pi zero w. Thanks
I want to measure voltage of
I want to measure voltage of a simple battery (cell). After researching and googling, measuring the battery voltage require an adc. I want to send the voltage data to cloud. A0 and A1 pins are used to find the potential difference (voltage) of one battery.
Will this work?
query ...plz help
nice tutorial sir ... i follow each step and my script is executing successfully ... but unable to display graph on screen ... I already installed matplotlib. plz help me as I am new to all this .. currently using raspberry pi 3 , Python 3.5
thanks in advance
Because pi has two pythons usually
The two pythons are python 2 and python 3
if you want matplotlib to work with python 3. When downloading pip has to be pip3 and you need to specify python3 rather than python.
So the above instructions are
Using alternative ADC
I have a MCP3008 chip so have altered your program to suit.
Good Work! But it's been too
Good Work! But it's been too slow to show higher frequencies than 0,5Hz.
I've changed the code a little bit, because the "drawnow" function takes too much time.
import time
import matplotlib.pyplot as plt
#import numpy
from drawnow import *
# Import the ADS1x15 module.
import Adafruit_ADS1x15
# Create an ADS1115 ADC (16-bit) instance.
adc = Adafruit_ADS1x15.ADS1115()
GAIN = 1
val = [ ]
plt.ion()
# Start continuous ADC conversions on channel 0 using the previous gain value.
adc.start_adc(0, gain=GAIN,data_rate=860)
print('Reading ADS1x15 channel 0')
#create the figure function
def makeFig():
plt.ylim(-5000,5000)
plt.title('Oscilloscope')
plt.grid(True)
plt.ylabel('ADC outputs')
plt.plot(val, 'ro-', label='Channel 0')
plt.legend(loc='lower right')
while (True):
for i in range(200):
value = adc.read_adc(0, gain=GAIN, data_rate=860)
print('Channel 0: {0}'.format(value))
val.append(int(value))
drawnow(makeFig)
for e in range(200):
val.pop(0)
after running the code i…
after running the code i keep getting this error :
RuntimeError: Could not determine default I2C bus for platform
can anybody tell me whats wrong please
I just finished with the…
I just finished with the code, but after a few tries I still don't know what is the lowest sleep time I can imput. I tried to go lower than .5 but I don't really see any differences. Is there possible to go to 0.01 or lower? Or with this configuration this is the fastest time you can get on the reading?
I so, can you help with a low price alternative or component to help getting a faster read? Thanks
I cannot get the code to run…
I cannot get the code to run. I suspect it's a numpy error but I don't know how to fix it.
I'm running Raspberry Pi os, 32-bit, on a RPi Zero W with Python3 installed plus all the required items.
This works properly: python simpletest.py
I get the following error:
pi@RPIzero2:~ $ sudo python scope.py
RuntimeError: module compiled against API version 0x10 but this version of numpy is 0xd
Traceback (most recent call last):
File "/home/pi/scope.py", line 3, in <module>
import matplotlib.pyplot as plt
File "/usr/local/lib/python3.9/dist-packages/matplotlib/__init__.py", line 113, in <module>
from . import _api, _version, cbook, _docstring, rcsetup
File "/usr/local/lib/python3.9/dist-packages/matplotlib/rcsetup.py", line 27, in <module>
from matplotlib.colors import Colormap, is_color_like
File "/usr/local/lib/python3.9/dist-packages/matplotlib/colors.py", line 56, in <module>
from matplotlib import _api, _cm, cbook, scale
File "/usr/local/lib/python3.9/dist-packages/matplotlib/scale.py", line 22, in <module>
from matplotlib.ticker import (
File "/usr/local/lib/python3.9/dist-packages/matplotlib/ticker.py", line 138, in <module>
from matplotlib import transforms as mtransforms
File "/usr/local/lib/python3.9/dist-packages/matplotlib/transforms.py", line 49, in <module>
from matplotlib._path import (
ImportError: numpy.core.multiarray failed to import
pi@RPIzero2:~ $
Any help would be appreciated!
I love your project, I am going to have to build this in the very near future. Thanks!!!