Wiring
We'll be using the LSM6DSOX sensor to precisely measure acceleration data. The MCP2221 and LSM6DSOX both have STEMMA QT connectors, so you can either wire it up on a breadboard or use a STEMMA QT cable.


Make the following connections between the MCP2221 and the LSM6DSOX:
- Board 3V to sensor VIN (red wire)
- Board GND to sensor GND (black wire)
- Board SCL to sensor SCL (yellow wire)
- Board SDA to sensor SDA (blue wire)
Then, download the example notebook:
Code Usage
In the Jupyter file browser, click Upload. From the file browser, select the LSM6DSOX_Accel.ipynb example.
Click the Run button to execute the first cell. This cell installs the required libraries for using this notebook.
This cell installs the adafruit-circuitpython-lsm6dsox
library for interfacing with the LSM303 sensor .
This cell also installs a Jupyter Extension, ipympl
. This extension makes it possible for us to create interactive Matplotlib graphs from within a Jupyter notebook.
The next cell sets an environment variable so Blinka knows we're using the MCP2221.
Then, it imports CircuitPython libraries and initializes the I2C connection with the sensor.
The next cell imports CircuitPython modules (such as board
and busio
) and initializes the i2c connection with the sensor. To verify that your board is properly initialized, it should also values form the LSM6DSOX's acceleration sensor.
The next cell sets an environment variable so Blinka knows we're using the MCP2221.
Then, it imports CircuitPython modules (such as board
and busio
) and initializes the i2c connection with the sensor. To verify that your board is properly initialized, it should also print values from the LSM6DSOX acceleration sensor.
If you receive an error with the board
module, make sure your MCP2221 is plugged into a usb port on your computer.
The third code cell uses Matplotlib to generate a graph for the LSM6DSOX's acceleration data. We used three side-by-side subplots to visualize the X, Y, and Z axis.
Increasing the Number of Sensor Readings
By default, this code cell only displays 20 sensor readings. If you want to display more sensor readings on your graph, simply change the value of the HISTORY_SIZE
variable in the code cell and re-run it.
For more information about how this code cell works, read on!
Code Walkthrough
First, we import all required libraries for this code cell. Most of the libraries come from the Matplotlib library. We use this library to plot the data obtained by our sensor.
%matplotlib notebook import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import datetime import matplotlib.dates as mdates from collections import deque
Our code only plots and displays 20 sensor readings at a time. We store these readings in a list-like object called a deque
container datatype. If you've never seen this datatype before, don't worry - it's very similar to a list
object except it's "optimized for fast fixed-length operations" and support a maxlen
argument which sets the maximum possible size of a deque. When the deque grows beyond its maxlen
size, it pops objects off of its opposite end (like a FIFO stack).
We'll be using four deque objects to represent the x-axis, the first graph's y-axis (accelerometer's x-axis data), the second graph's y-axis (accelerometer's y-axis data), and the third graph's y-axis (accelerometer's y-axis data). These deque objects use HISTORY_SIZE
as the deque's maxlen
. You may increase the amount of data to display on the graph by increasing HISTORY_SIZE
.
# Deque for X-Axis (time) x_vals = deque(maxlen=HISTORY_SIZE) # Deque for Y-Axis (accelerometer readings) accel_x = deque(maxlen=HISTORY_SIZE) accel_y = deque(maxlen=HISTORY_SIZE) accel_z = deque(maxlen=HISTORY_SIZE)
Next, we'll create three side-by-side sub-plots and call tight_layout
to adjust the subplot parameters to give nicer padding between examples.
# Create 3 side-by-side subplots fig, (ax1, ax2, ax3) = plt.subplots(1,3) # Automatically adjust subplot parameters for nicer padding between plots plt.tight_layout()
Let's now take a look at the animate
method. This method polls the LSM303's acceleration values and stores them in a tuple named accel_data
. Next, the code appends the values from the tuple to deque
objects, accel_x
, accel_y
, accel_z
.
def animate(i): # Poll the LSM303AGR accel_data = accel.acceleration # Add the X/Y/Z values to the accel arrays accel_x.append(accel_data[0]) accel_y.append(accel_data[1]) accel_z.append(accel_data[2])
We grab the current time (in seconds using CPython's datetime
module) and store it in a deque, x_vals
.
# Grab the datetime, auto-range based on length of accel_x array x_vals = [datetime.datetime.now() + datetime.timedelta(seconds=i) for i in range(len(accel_x))]
Now we're up to the fun part of this code walkthrough - displaying the graphs. Since we're "animating" the graph, the axis will need to be cleared and re-drawn each time the animate
method runs. Let's clear the three axis, set up grid titles and enable grid lines.
# Clear all axis ax1.cla() ax2.cla() ax3.cla() # Set grid titles ax1.set_title('X', fontsize=10) ax2.set_title('Y', fontsize=10) ax3.set_title('Z', fontsize=10) # Enable subplot grid lines ax1.grid(True, linewidth=0.5, linestyle=':') ax2.grid(True, linewidth=0.5, linestyle=':') ax3.grid(True, linewidth=0.5, linestyle=':')
Since we are displaying a large amount of data on the x-axis, we'll use Matplotlib's autofmt_xdate()
method to automatically align and roate the x-axis labels.
The first image on the left shows this code without a call to autofmt_xdate
while the second image shows a nicely formatted graph. Pretty neat, right
Finally, we'll display the sub-plots on the figure by calling ax.plot
and specifying the x-axis and y-axis deques. We'll also specify different colors for each graphs to help us visually identify the sub-graphs.
# Display the sub-plots ax1.plot(x_vals, accel_x, color='r') ax2.plot(x_vals, accel_y, color='g') ax3.plot(x_vals, accel_z, color='b')
Finally, we'll pause the plot's drawing for INTERVAL
seconds.
# Pause the plot for INTERVAL seconds plt.pause(INTERVAL)
About Notebook Performance
Computers with less available resources will render choppy graphs. For reference, all GIFs in this guide were rendered on a computer with a 2.6GHz i7 and 32GB of RAM.
We can increase the INTERVAL
, keeping in mind two things:
- USB is limited to one transaction per millisecond
- We are displaying
HISTORY_SIZE
samples at a time. You may want to decrease the number of samples displayed on the graph for better performance.
This method "makes an animation by repeatedly calling a function", animate
. We provide it the figure we generated earlier and the function we'd like to animate.
# Update graph every 125ms ani = FuncAnimation(fig, animate)