Intro: Using an Arduino and Python to Plot/save Data
A quick and easy way to see (and then save) data taken using an Arduino onto your computer.
(Note: not the most robust method, but it works well enough)
- Arduino (I’m using an Uno)
- Computer (I have a Dell, but it shouldn’t really matter if you are running Windows. Otherwise, you’ll need to make some minor edits to the Python code.)
- Python, including the matplotlib, pyserial, and numpy extensions
- Some sort of sensor/input device (I’m using an ADXL335 accelerometer)
Step 1: Wiring the Circuit
This accelerometer is extremely simple to use. It is powered off of 5VDC and each output pin (X, Y, Z) gives an analog voltage from 0-3V depending on the measured acceleration. To power it, simply connect the 5V output pin and one of the GND pins of the Arduino to the Vin pin and GND pin on the accelerometer. The X, Y, and Z pins go to any three of the analog input pins on the Arduino (I used A1, A2, and A3).
You can leave the setup like this, but the analog pins on the Arduino range from 0-5V, while the accelerometer ranges from 0-3V. This means that you will only be using about half of the range of possible analog values and will have less precision in your measurements. Ideally, the ranges would be the same so the full range of analog values is available.
The Arduino range can be changed by connecting a new reference voltage to the AREF pin and signifying in the code that the analog reference is external (see step 2). I didn't care too much about precision, so I just used the 3.3V output on the Arduino as my reference voltage, but the 3V output on the accelerometer should work as well.
Step 2: Arduino Code
The Arduino simply reads in the values on all three analog pins and sends them over serial to the computer. Tabs are added between the data to make it easier to read on the computer side.
The only setup required (other than declaring variables) is to create the serial connection at a baud rate of 9600 and declare the analog reference to be external, as mentioned earlier.
This code reads in values on analog pins A1-A3 and sends the values
over serial. The outputs can be checked using the serial monitor.
const int xpin = A3; // x-axis
const int ypin = A2; // y-axis
const int zpin = A1; // z-axis
Serial.begin(9600); //setup serial connection
analogReference(EXTERNAL); //set external reference point for analog pins
Serial.print(analogRead(xpin)); //read xpin and send value over serial
Serial.print("\t"); //send a "tab" over serial
Serial.println(); //ends the line of serial communication
Step 3: Python Code
The Python code reads the incoming serial data, and separates each line along the tabs, giving you separate values for the X, Y, and Z data. Some processing is done to put the values into their own variables.
To plot the variables, the “matplotlib” library is used to create an animated graph. This results in a reasonably accurate “live feed”, but large amounts of sensor activity will cause the graph to lag a bit.
Finally, the data is saved to a .txt file in a specified location. The data can then be read back when needed using the numpy.loadtxt() function (see next step for code). However, this file type is most easily read in Python, so if you want to open the data in a different program you’ll need to use a different write function. (ex. Use .csv file format to open data in Excel) Don't forget to change the file location to match your computer's directory.
See the code for more detailed comments (or Google or ask and I’ll do my best to explain or point you to an explanation)
Reads in data over a serial connection and plots the results live. Before closing, the data is saved to a .txt file.
import matplotlib.pyplot as plt
import numpy as np
connected = False
#finds COM port that the Arduino is on (assumes only one Arduino is connected)
wmi = win32com.client.GetObject("winmgmts:")
for port in wmi.InstancesOf("Win32_SerialPort"):
#print port.Name #port.DeviceID, port.Name
if "Arduino" in port.Name:
comPort = port.DeviceID
print comPort, "is Arduino"
ser = serial.Serial(comPort, 9600) #sets up serial connection (make sure baud rate is correct - matches Arduino)
while not connected:
serin = ser.read()
connected = True
plt.ion() #sets plot to animation mode
length = 500 #determines length of data taking session (in data points)
x = *length #create empty variable of length of test
y = *length
z = *length
xline, = plt.plot(x) #sets up future lines to be modified
yline, = plt.plot(y)
zline, = plt.plot(z)
plt.ylim(400,700) #sets the y axis limits
for i in range(length): #while you are taking data
data = ser.readline() #reads until it gets a carriage return. MAKE SURE THERE IS A CARRIAGE RETURN OR IT READS FOREVER
sep = data.split() #splits string into a list at the tabs
x.append(int(sep)) #add new value as int to current list
xline.set_xdata(np.arange(len(x))) #sets xdata to new list length
xline.set_ydata(x) #sets ydata to new list
plt.pause(0.001) #in seconds
plt.draw() #draws new plot
rows = zip(x, y, z) #combines lists together
row_arr = np.array(rows) #creates array from list
np.savetxt("C:\\Users\\mel\\Documents\\Instructables\\test_radio2.txt", row_arr) #save data in file (load w/np.loadtxt())
ser.close() #closes serial connection (very important to do this! if you have an error partway through the code, type this into the cmd line to close the connection)
Step 4: Results
This is just the most basic plot - you can easily add axes labels, legend, etc. using matplotlib (just Google for it). I simply rotated the X axis to +/-1g for this test. When it's running, the plot will update constantly to show live movement.
Step 5: Reading Back the Data
To read back the data saved with numpy.savetxt(), you use numpy.loadtxt() and assign it to a variable. The variable can then be manipulated and re-plotted (in my case, I have the "markers" option set so I can see the individual data points).
Reads and plots data from a .txt file
import matplotlib.pyplot as plt
import numpy as np
#load values from file into "data"
data = np.loadtxt("C:\\Users\\me\\Documents\\Instructables\\test.txt")
#create empty lists for data to be sorted into
x = 
y = 
z = 
#for each line in data, sort it into the appropriate list
for dat in data:
#plot each list then show the plot
plt.plot(x, marker = 'o')
plt.plot(y, marker = 'o')
plt.plot(z, marker = 'o')