In this guide we will show how to get the a BerryIMUv3 working with a Raspberry Pi Pico, using MicroPython. This code example supports I2C and SPI.
Hook up Guide
The two images below show how to hook up the BerryIMUv3 via I2C or SPI. (If using SPI, you will need to place a solder "blob" on JP7 on the BerryIMUv3 to complete the SPI connection, as shown here)
Raspberry Pi Pico and BerryIMv3 via SPI
Raspberry Pi Pico and BerryIMv3 via I2C
Thonny and the MicroPython code
The MicroPython code can be downloaded from our GitHub repository. The code for this example can be found under the PicoMicroPython directory.
We will be using Thonny to program the Raspberry Pi Pico.
The sample code supports both I2C and SPI communications. Comment out the protocol which will not be used as shown below. Below we have commented out I2C as we will be using SPI
import utime
import math
from LSM6DSL import *
import machine
#Comment out one of the below lines
import IMU_SPI as IMU
#import IMU_I2C as IMU
The accelerometer(LSM6DSL) on the BerryIMUv3 has built in double tap detection, which makes it very easy to detect double taps without the need for any fancy code.
When the LSM6DSL detects a double tap, it can fire an interrupt pin on the BerryIMUv3. We will use a Raspberry Pi to monitor the interrupt pin and turn a LED off and on when a double-tap is detected.
Double-Tap event recognition has special registers which control tap recognition functionality, these are the tap threshold and the Shock, Quiet and Duration time windows
Double-tap event recognition
The Raspberry Pi will configure the BerryIMUv3 for double tap recognition. It will also monitor for double taps, which will be used to turn a LED on and off.
INT1 On the BerryIMUv3 will go high when a double tap is detected.
GPIO18 (physical pin 12) on the Raspberry Pi will be used to monitor INT1 , using an interrupt.
GPIO20 (physical pin 28) will be used to drive the LED.
The resister below is 330 Ohms
Here is the hock up diagrams
BerryIMU double-tap using QWIIC cableBerryIMU double-tap
import signal
from LSM6DSL import *
import sys
import RPi.GPIO as GPIO
import smbus
bus = smbus.SMBus(1)
LED_ON = 0 #Used to track of the current state of the LED
INTERRUPT_PIN = 12 #The interrupt pin which will be connected to the IMU
LED_PIN = 38 #The pin which will be driving the LED
#Used to clean up when Ctrl-c is pressed
def signal_handler(sig, frame):
GPIO.cleanup()
sys.exit(0)
#Used to write to the IMU
def writeByte(device_address,register,value):
bus.write_byte_data(device_address, register, value)
def LEDnotification(channel):
global LED_ON
if LED_ON:
GPIO.output(LED_PIN,0)
LED_ON = 0
else:
GPIO.output(LED_PIN,1)
LED_ON = 1
writeByte(LSM6DSL_ADDRESS,LSM6DSL_CTRL1_XL,0b01100000) #ODR_XL = 416 Hz, FS_XL = +/- 2 g
writeByte(LSM6DSL_ADDRESS,LSM6DSL_TAP_CFG,0b10001110) #Enable interrupts and tap detection on X, Y, Z-axis
writeByte(LSM6DSL_ADDRESS,LSM6DSL_TAP_THS_6D,0b10001100) #Set tap threshold
writeByte(LSM6DSL_ADDRESS,LSM6DSL_INT_DUR2,0b01111111) #Set Duration, Quiet and Shock time windows
writeByte(LSM6DSL_ADDRESS,LSM6DSL_WAKE_UP_THS,0b10000000) #Double-tap enabled
writeByte(LSM6DSL_ADDRESS,LSM6DSL_MD1_CFG,0b00001000) #Double-tap interrupt driven to INT1 pin
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
GPIO.setup(INTERRUPT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(LED_PIN, GPIO.OUT)
GPIO.output(LED_PIN, 0)
GPIO.add_event_detect(INTERRUPT_PIN, GPIO.RISING, callback=LEDnotification, bouncetime=300)
while True:
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
We will cover specific code which relates to double-tap recognition.
Line 37, LSM6DSL_TAP_CFG is used to enable tap recognition on the X, Y, Z directions. It is also used to enable the interrupt function for double-tap recognition.
Line 38, LSM6DSL_TAP_THS_6D is used to set the tap thresholds. a lower value will result in softer taps being detected.
Line 39, LSM6DS_INT_DUR2 is used to set the duration, quiet and shock time window. A larger duration will result in a longer time between 1st and 2nd tap.
Line 40, LSM6DSL_WAKE_UP_THS. Set the left most bit to enable double tap recognition.
Line 41, LSM6DSL_MD1_CFG is used to set which interrupt pin ont he BerryIMUv3 is used. In this instance, it is set to INT1.
u-Center from u-Blox is a graphical interface which can be used to monitor and configure all aspects of the GPS module on a BerryGPS-IMU or BerryGPS-GSM.
U-Center
u-Center only runs on Windows. It can connect over the network to a Raspberry Pi. This will require us to redirect the serial interface on the Raspberry Pi to a network port using ser2net.
Once installed, open u-Center. You will get the default view as shown below. No data will be shown as we are not connected to a GPS.
The next step, is to create a new network connection and connect to the GPS which is connected to our Raspberry Pi. You can create a new connection under the Receiver and thenNetwork connection menus.
In the new window, enter the IP address of the Raspberry Pi and specify port 6000. This is the port we configured in ser2net on the Raspberry Pi.
This is what the default view looks like when connected and the GPS has a fix.
u-Center
Below I will list of the more useful windows/tools within u-Center. You can also click on the images below for a larger version.
Data View This window will show you the longitude, latitude, altitude and fix mode. It will also show the HDOP, which is the Horizontal Dilution of Precision. Lower is better, anything below 1.0 means you have a good signal.
u-Center Data View
Ground Track This window will show you where the satellites are as well as what time.
u-Center Ground Track
Skye View Sky view is an excellent tool for analyzing the performance of antennas as well as the conditions of the satellite observation environment.
u-Center Sky View
Deviation Map This map shows the average of all previously measured positions.
In this guide we will show you how to control the GPIO pins of a Raspberry pi by send a SMS to the Raspberry Pi from a mobile phone.
For this guide, the GSM modem we are using to receive the SMS is the BerryGPS-GSM.
On the software side, we will be using Gammu, which is specifically designed to control phones and GSM modules. It also has a daemon which will monitor the GSM modem for incoming SMSs.
We will configure Gammu to trigger a python script when a new SMS is received. We will use the contents of the SMS to control what happens in Python
LEDs are used here as an example, but you can do anything you like Eg. Open a garage door, turn on some lights, etc..
Wiring
We will be using the three bottom right GPIO pins on the Raspberry Pi header. These are GPIO 16, 20 and 21. Each is connected to a different color LED as shown above. The The resistors used are 330 Ohm and the GND pin (shorter pin) of the LEDs is connected to the GND power rail.
Send a test SMS to a mobile number. The mobile number below is an example, you will need to update this;
pi@raspberrypi ~ $ echo "This is a test from a Raspberry Pi" | /usr/bin/gammu --sendsms TEXT +614123456789
Python Script
This python script will run every time a new SMS is received.
pi@raspberrypi ~ $ nano ~/smsReceived.py
Copy in the below code
import RPi.GPIO as GPIO
import time
import sys
import re
RED_LED = 21
GREEN_LED = 20
BLUE_LED = 16
GPIO.setmode(GPIO.BCM)
filename=str(sys.argv[1]) #Gammu will pass the filename of the new SMS as an argument
complete_filename="/var/spool/gammu/inbox/"+filename #we create the full path to the file here
GPIO.setup(RED_LED , GPIO.OUT)
GPIO.setup(GREEN_LED , GPIO.OUT)
GPIO.setup(BLUE_LED , GPIO.OUT)
sms_file=open(complete_filename,"r")
#read the contents of the SMS file
message=sms_file.read(160) #note that a not-parted SMS can be maximum 160 characters
#search the contents and perform an action. Rather than use 'find',
# we will use regular expression (re) so we can ignore case.
#Most smartphones will have the first letter capitalised
if re.search('red', message, re.IGNORECASE):
GPIO.output(RED_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(RED_LED , GPIO.LOW)
elif re.search('green', message, re.IGNORECASE):
GPIO.output(GREEN_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(GREEN_LED , GPIO.LOW)
elif re.search('blue', message, re.IGNORECASE):
GPIO.output(BLUE_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(BLUE_LED , GPIO.LOW)
GPIO.cleanup()
In this guide we will show you how to send a SMS using a button connected to the GPIO pins of a Rasberry Pi Zero.
For this guide, the GSM modem we are using to send the SMS is the BerryGPS-GSM.
On the software side, we will be using Gammu, which is specifically designed to control phones and GSM modules.
Python will be used to monitor some buttons connected to GPIO pins and Gammu python bindings will be used to send a SMS.
Buttons are used here as an example, but you can use anything to trigger the SMS, E.g. Temperature sensor, water level sensor, light sensor, etc..
We have includes some LEDs so we can see when the buttons are pressed.
Wiring
We will be using the three bottom right GPIO pins on the Raspberry Pi header. These are GPIO 16, 20 and 21. Each is connected to a button and different color LED as shown above. The internal pull-down resisters will be used on these GPIO. 3.3v and GND are connect to the power rails on the breadboard. The resistors used are 330 Ohm and the GND pin (shorter pin) of the LEDs is connected to the GND power rail.
Typically, a GPS module can take a few minutes to get Time To First Fix(TTFF), or even longer if you are in built up areas(+20mins). This is because the Almanac needs to be downloaded from satellites before a GPS fix can be acquired and only a small portion of the Almanac is sent in each GPS update.
Assisted GPS speeds this up significantly by downloading ephemeris, almanac, accurate time and satellite status over the network, resulting in faster TTTF, in a few seconds. This is very similar how to GPS works on a smartphone.
The BerryGPS-GSM supports assisted GPS. The below video shows a comparison between assisted and normal GPS.
The SARA-U201 can be configured to download GPS assist data and then pass this over the the GPS module. These two components speak to each other via i2c.
This assist data is downloaded by the SARA-U201 modem (not the Pi), therefore the modem needs to create an internal PDP (Packet Data Protocol) connection.
Once the PDP connection is made, the SARA-U201 will reach out to uBlox AssitNow servers and download the latest assist data. A valid token is needed to perform this, all BerryGPS-GSM have had this token pre-configured.
Here are three examples of how to use python to get GPS data from a GPS receiver attached to a Raspberry Pi.
Using GPSD client libraries
Manually parsing NMEA sentences
Using pynmea2 to parse NMEA sentences
GPSD client libraries
The gpsd client libraries are based on JSON. The JSON objects have a "class" attribute (E.g. TPV, SKY, DEVICE.etc...) which can be used to filter on different information.
This guide shows how to get gpsd up an running on a Raspberry Pi.
The example python script below filters on the TPV class, which is the Time Position Velocity report and then prints out the relevant information.
#! /usr/bin/python
from gps import *
import time
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
print 'latitude\tlongitude\ttime utc\t\t\taltitude\tepv\tept\tspeed\tclimb' # '\t' = TAB to try and output the data in columns.
try:
while True:
report = gpsd.next() #
if report['class'] == 'TPV':
print getattr(report,'lat',0.0),"\t",
print getattr(report,'lon',0.0),"\t",
print getattr(report,'time',''),"\t",
print getattr(report,'alt','nan'),"\t\t",
print getattr(report,'epv','nan'),"\t",
print getattr(report,'ept','nan'),"\t",
print getattr(report,'speed','nan'),"\t",
print getattr(report,'climb','nan'),"\t"
time.sleep(1)
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "Done.\nExiting."
This python script filters on the SKY class and prints out satellite information.
#! /usr/bin/python
from gps import *
import time
import os
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
try:
while True:
report = gpsd.next() #
if report['class'] == 'SKY':
os.system('clear')
print ' Satellites (total of', len(gpsd.satellites) , ' in view)'
for i in gpsd.satellites:
print 't', i
print '\n\n'
print 'PRN = PRN ID of the satellite. 1-63 are GNSS satellites, 64-96 are GLONASS satellites, 100-164 are SBAS satellites'
print 'E = Elevation in degrees'
print 'As = Azimuth, degrees from true north'
print 'ss = Signal stength in dB'
print 'used = Used in current solution?'
time.sleep(1)
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "Done.\nExiting."
Manually parsing NMEA sentences
The python script below shows how to access GPS data by connecting directly to the serial interface. It filters on $GPRMC NMEA sentences and then splits the well know attributes into different variables.
import serial
port = "/dev/serial0"
def parseGPS(data):
# print "raw:", data #prints raw data
if data[0:6] == "$GPRMC":
sdata = data.split(",")
if sdata[2] == 'V':
print "no satellite data available"
return
print "---Parsing GPRMC---",
time = sdata[1][0:2] + ":" + sdata[1][2:4] + ":" + sdata[1][4:6]
lat = decode(sdata[3]) #latitude
dirLat = sdata[4] #latitude direction N/S
lon = decode(sdata[5]) #longitute
dirLon = sdata[6] #longitude direction E/W
speed = sdata[7] #Speed in knots
trCourse = sdata[8] #True course
date = sdata[9][0:2] + "/" + sdata[9][2:4] + "/" + sdata[9][4:6]#date
print "time : %s, latitude : %s(%s), longitude : %s(%s), speed : %s, True Course : %s, Date : %s" % (time,lat,dirLat,lon,dirLon,speed,trCourse,date)
def decode(coord):
#Converts DDDMM.MMMMM > DD deg MM.MMMMM min
x = coord.split(".")
head = x[0]
tail = x[1]
deg = head[0:-2]
min = head[-2:]
return deg + " deg " + min + "." + tail + " min"
print "Receiving GPS data"
ser = serial.Serial(port, baudrate = 9600, timeout = 0.5)
while True:
data = ser.readline()
parseGPS(data)
Using pynmea2 to parse NMEA sentences
The python script below shows how to access GPS data by connecting directly to the serial interface. It filters on $GPGGA NMEA sentences and then uses pynmea2 to parse the data.
Navit is an open source navigation system with GPS tracking. It works great with a Raspberry Pi, a GPS module and a small TFT with touch, jut like the official Raspberry Pi Display or PiScreen.
Navit can be installed without a GPS connected to your Raspberry Pi, but you will not be able to use the real-time turn by turn navigation. You will however be able to browse maps. If you are not going to use a GPS, you can skip to the next step.
As we are using the BerryGPS-IMU, we will be following the guide in the link below. As most GPS modules use serial to communication, this guide can be followed for other GPS modules.
The images below shows how we have connected the BerryGPS-IMU to the Raspberry Pi 3 whilst it is in the SmartPi Touch case.
If you plan on testing this out in your car, you need to be mindfully of where you place your BerryGPS. In my setup and I have placed it in the air vent as shown below, and BerryGPS gets a good strong signal.
If you are using an external antenna, then there is no need to worry about where your BerryGPS is placed.
BerryIMU also works great with Windows IoT Core on the Raspberry Pi.
Our Git repository contains the source files needed to get the BerryIMU up and running on Windows IoT.
The code will print out the following values to the screen;
Raw values from the gyroscope, accelerometer and magnetometer.
Accelerometer calculated angles.
Gyro tracked angles.
Fused X and Y angles.
Heading.
Tilt compensated heading.
Connecting BerryIMU to a Raspberry Pi
BrryIMU can connect via the jumper cables to the Raspberry Pi as shown below;
Or BerryIMU can sit right on top of the GPIO pins on a Raspberry Pi. The first 6 GPIOs are used as shown below.
Get the Code
Download the BerryIMU code for Windows IoT from our GIT repository. The files you need are under the WindowsIoT-BerryIMU folder.
You will need to download the entire git repository as GIT doesn't allow downloading individual folders.
Once downloaded, double-click the file WindowsIoT-BerryIMU.sln to open up the project in Visual Studio.
About the code
The project code outputs all of the needed values to the screen and a complementary filter is used to fuse the accelerometer and gyroscope angles.
We have a number of guides already documented on how to get the BerryIMU working with the Raspberry Pi. https://ozzmaker.com/berryimu/ These are based on Raspbian, however the principals and math are the same for Windows Iot.
The final values which should be used are the fused X &Y angles and the tilt compensated heading.
The sensor on the BerryIMU is the LSM9DS0 and all the I2C registers for this sensor can be found in LSM9DS0.cs
The main code can be found in MainPage.xaml.cs
Complementary Filter
A complementary filter is used to fuse the angles. Is summary, the complementary filter trusts the gyroscope for short periods and trusts the accelerometer for longer periods;
Changing how much trust is given for each of the sensors can be changed by modify the complementary filter constant at the start of the code.
const float AA = 0.03f; // Complementary filter constant
Loop Speed
The loop speed is important as we need to know how much time has past to calculate the rotational degrees per second on the gyroscope. A time delta is set at the start of the code.
const int DT = 100; //DT is the loop delta in milliseconds.
This is then used to specify a new timer method.
periodicTimer = new Timer(this.TimerCallback, null, 0,DT);
Here you can see where DT is used to keep track of the gyroscope angle. You can also see it in the above calculation for the complementary filter.
//Calculate the angles from the gyro
gyroXangle += rate_gyr_x * DT / 1000;
gyroYangle += rate_gyr_y * DT / 1000;
gyroZangle += rate_gyr_z * DT / 1000;
BerryIMU orientation
The calculations in the code are based on how the BerryIMU is orientated. If BerryIMU is upside down, then some of the angles need to be reversed. It is upside down when the skull logo is facing up(or to the sky). If it is upside down, set the below value to true. Otherwise, set it to false.