Using Accelerometer to Determine Device Orientation - with the RasPi Kit

Using Accelerometer to Determine Device Orientation - with the RasPi Kit

This project demonstrates how to use the SI02 Accelerometers build-in Portrait/Landscape mode as well as the Front and Back mode.

The SI02 xChip has both a Magnetometer and a Accelerometer, but in this example we are focused on the Accelerometer. It is based on the 10-bit version of NXP's MMA8x5x series of Accelerometers, more specifically the MMA8653FC. You can read much more about the SI02 on our Wiki, including finding data sheets and other links.

This project is also using our OD01 xChip 128x64 pixel OLED. Here we are using the Luma library by Richard Hull. You can see more about installing this library in this Hackster project.

And finally we use a BR01 xChip which bridges the XinaBox xChip with an ordinary Raspberry Pi.

Instead of calculating portrait and landscape and what is front and back, we read a register on the chip, telling us how we should interpret the position of the kit. We then use the Luma library to display a analog (and digital) watch on the OLED automatically oriented to maximise readability - exactly like your smartphone does when you look at pictures and videos. We also read the front and back register and use this to show the clock in positive or negative colours.

Watch this video and find the code below:

import smbus2 as smbus
import time
import math
import datetime
from luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1306, ssd1325, ssd1331, sh1106
from luma.core import legacy
from luma.core.legacy.font import proportional, CP437_FONT, LCD_FONT

serial = i2c(port=1, address=0x3C)

def bit1(byte, bitno):
    if byte & 2**bitno:
        return True
    else:
        return False

def bit0(byte,bitno):
    if byte & 2**bitno:
        return False
    else:
        return True

def posn(angle, arm_length):
    dx = int(math.cos(math.radians(angle)) * arm_length)
    dy = int(math.sin(math.radians(angle)) * arm_length)
    return (dx, dy)

bus = smbus.SMBus(1)

#StandBy mode
bus.write_byte_data(0x1d, 0x2A, 0x00)
#Activate Portrait/Landscape
bus.write_byte_data(0x1d, 0x11, 0b11000000)
#Active mode
bus.write_byte_data(0x1d, 0x2A, 0x01)

today_last_time = "Unknown"
direction=0
fg="white"
bg="black"
device = ssd1306(serial, rotate=direction)
while(1):
    now = datetime.datetime.now()
    today_date = now.strftime("%d %b %y")
    today_time = now.strftime("%H:%M:%S")
    plreg = bus.read_i2c_block_data(0x1d, 0x10, 1)[0]
    if bit1(plreg,7): 
        if bit1(plreg,2) and bit1(plreg,1): direction = 0
        if bit1(plreg,2) and bit0(plreg,1): direction = 2
        if bit0(plreg,2) and bit1(plreg,1): direction = 1 
        if bit0(plreg,2) and bit0(plreg,1): direction = 3
        if bit0(plreg,0):
            bg="black"
            fg="white"
        if bit1(plreg,0): 
            fg="black"
            bg="white"
        device = ssd1306(serial, rotate=direction)


    if today_time != today_last_time:
        today_last_time = today_time
        with canvas(device) as draw:
            now = datetime.datetime.now()
            today_date = now.strftime("%d %b %y")

            margin = 4

            cx = 32
            cy = min(device.height, 64) / 2

            left = cx - cy
            right = cx + cy

            hrs_angle = 270 + (30 * (now.hour + (now.minute / 60.0)))
            hrs = posn(hrs_angle, cy - margin - 7)

            min_angle = 270 + (6 * now.minute)
            mins = posn(min_angle, cy - margin - 2)

            sec_angle = 270 + (6 * now.second)
            secs = posn(sec_angle, cy - margin - 2)

            draw.rectangle(device.bounding_box, outline=fg, fill=bg)
            draw.ellipse((left + margin, margin, right - margin, min(device.height, 64) - margin), outline=fg)
            draw.line((cx, cy, cx + hrs[0], cy + hrs[1]), fill=fg)
            draw.line((cx, cy, cx + mins[0], cy + mins[1]), fill=fg)
            draw.line((cx, cy, cx + secs[0], cy + secs[1]), fill=fg)
            draw.ellipse((cx - 2, cy - 2, cx + 2, cy + 2), fill=fg, outline=fg)
            if direction == 0 or direction == 2:
                draw.text((2 * (cx + margin), cy - 8), today_date, fill=fg)
                draw.text((2 * (cx + margin)+2, cy), today_time, fill=fg)
            else:
                cy += 64
                draw.text((5, cy - 8), today_date, fill=fg)
                draw.text((5+2, cy), today_time, fill=fg)

        time.sleep(0.1)

 

Please see our Raspberry Pi XK03 kit, and especially the online instructions for other useful links to getting started, sample code and projects.

Next article Tinder Maths with XinaBox and the Raspberry Pi