Thursday, June 6, 2013

GPS for the Beaglebone Black: D2523T 50 Channel Helical GPS Receiver

The 50 Channel D2523T Helical GPS Receiver is a pricier GPS choice at $79, but I find that it works better than the cheaper 50 Channel GP-635T GPS Receiver ($39). I live in a multistory building in downtown Minneapolis. I can only get the GP-635T to work (sometimes) out on my balcony.  D2523T Helical GPS Receiver works inside near a window or glass door. Once it has acquired a signal, I can move it 12 to 15 back from the door or window without losing the signal.

[Note: As of October, 2013, Sparkfun no longer carries thie D2523T, but a Google search will locate other sources.]

I'm using this interface cable to connect the D2523T GPS module to this GPS breakout on a breadboard.

Connections 


GPS Breakout  Beaglebone Black
Pin 3 (3V3)   P9 3
Pin 4 (GND)   P9 1
Pin 5 (TX)    P9 26
Pin 6 (RX)    P9 24

See this post for the configuration needed to use the Beaglebone Black's pins for serial (UART) communication.


Python Code


The following code pulls the latitude and longitude from the $GPRMC sentence.

import serial
import time
import datetime
import re
import os

os.system("echo uart1 > /sys/devices/bone_capemgr.9/slots")

serial = serial.Serial("/dev/ttyO1", baudrate=9600)

resp = ""

while True:
        while (serial.inWaiting() > 0):
                resp += serial.read()
                if "\r\n" in resp:
                        if "$GPRMC" in resp:
                                data = resp.split(',')
                                info = data[3] + " " + data[4] + " " + data[5] + " " + data[6]
                                print info
                        resp = ""

Sunday, June 2, 2013

Reading Barometric Pressure with a Beaglebone Black & an Adafruit BMP085 Breakout Board

The Adafruit version of the BMP085 - BMP085 Barometric Pressure/Temperature/Altitude Sensor - is a barometer that connects to the Beaglebone Black via I2C.  The information on the Adafruit page says it is 5 volt ready, but it also works nicely with the 3.3 volt Beaglebone Black.

The example below shows how to read the barometric pressure (compensated for temperature and elevation above sea level). I've adapted this from the Adafruit library for the BMP085.


Connections


TMP085  Beaglebone Black
GND     P9 Pin 1
VIN     P9 Pin 3
SCL     P9 Pin 19
SDA     P9 Pin 20 


Python Code


import time
import smbus

bus = smbus.SMBus(1)
mode = 3
i2c_addr = 0x77

def read_word_signed(addr, reg):
msb = bus.read_byte_data(addr, reg)
if msb > 127: msb -= 256
lsb = bus.read_byte_data(addr, reg+1)
return (msb << 8) + lsb

def read_word_unsigned(addr, reg):
msb = bus.read_byte_data(addr, reg)
lsb = bus.read_byte_data(addr, reg+1)
return (msb << 8) + lsb

# Read factory programmed parameters
# These are used for calculations 
AC1 = read_word_signed(i2c_addr, 0xAA)
AC2 = read_word_signed(i2c_addr, 0xAC)
AC3 = read_word_signed(i2c_addr, 0xAE)
AC4 = read_word_unsigned(i2c_addr, 0xB0)
AC5 = read_word_unsigned(i2c_addr, 0xB2)
AC6 = read_word_unsigned(i2c_addr, 0xB4)
B1 = read_word_signed(i2c_addr, 0xB6)
B2 = read_word_signed(i2c_addr, 0xB8)
MB = read_word_signed(i2c_addr, 0xBA)
MC = read_word_signed(i2c_addr, 0xBC)
MD = read_word_signed(i2c_addr, 0xBE)

while True:
# read temperature cmd
bus.write_byte_data(i2c_addr, 0xF4, 0x2E) 
time.sleep(0.005)  # Wait 5ms
msb = bus.read_byte_data(i2c_addr, 0xF6)
lsb = bus.read_byte_data(i2c_addr, 0xF6+1)
raw_temp = (msb << 8) + lsb

X1 = ((raw_temp - AC6) * AC5) >> 15
X2 = (MC << 11) / (X1 + MD)
B5 = X1 + X2
# Read pressure cmd
bus.write_byte_data(i2c_addr, 0xF4, 0x34 + (1 << 6)) 
time.sleep(0.026)
msb = bus.read_byte_data(i2c_addr, 0xF6)
lsb = bus.read_byte_data(i2c_addr, 0xF6+1)
xlsb = bus.read_byte_data(i2c_addr, 0xF6+2)
raw_ps = ((msb << 16) + (lsb << 8) + xlsb) >> (8-mode)

B6 = B5 - 4000
X1 = (B2 * (B6 * B6) >> 12) >> 11
X2 = (AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((AC1 * 4 + X3) << 3) + 2) / 4
X1 = (AC3 * B6) >> 13
X2 = (B1 * ((B6 * B6) >> 12)) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (AC4 * (X3 + 32768)) >> 15
B7 = (raw_ps - B3) * (50000 >> mode)

if (B7 < 0x80000000):
p = (B7 * 2) / B4
else:
p = (B7 / B4) * 2

X1 = (p >> 8) * (p >> 8)
X1 = (X1 * 3038) >> 16
X2 = (-7357 * p) >> 16
# Pressure in Pascals
p = p + ((X1 + X2 + 3791) >> 4)
p = p * 0.000295333727 # Convert to inches Hg
# Adjust for elevation: Add 1200 Pa / 100 meters in elev.
# MPLS is 264m above sea level
# Converted to inches Hg this is 0.935
print p + 0.935 
time.sleep(10)