Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Sunday, 31 March 2013

Snowboard HUD Part 10 - Summary

This is the last post (for a while) in this series on hacking together a pair of Heads-Up-Display snowboard goggles. At some point in the future I might revisit this and add in some more sensors and update the display -- I still haven't added in the temperature sensor and there are some really easy things to do in Python to add more functionality (e.g. keeping track of maximum speed, stopwatch functionality etc). This picture shows all the components put together.



This video shows the goggles now that I've hot glued the MyVu components in. It's a bit of a mess and probably needs another layer of foam added around the outside to hide all the glue and put a bit more separation between your face and the MyVu.


I've also recorded one more video showing the view through the goggles.



So in summary, it seems it is possible to hack together something that approximates a pair of Heads-Up-Display snowboard goggles. Although I'm not too sure about actually carrying around all that kit for real.

Also probably best not to be strapping things to your face that could poke out your eyes during an accident. 

The full listing of parts for my hacked together version is below...

Raspberry Pi - RS Components £25.92
SD Card - RS Components - £7.79
Anker Astro 3E 10000mAh battery pack - Amazon - £29.99
2013 Rayzor Pro Goggles - Amazon - £19.59
Ultimate GPS Breakout - Cool Components - £28.54
MyVu glasses - ebay - about £40
USB to TTL to UART RS232 COM Cable - Anmazon £4.66
Various USB cables, bits of wire etc. less than £5

So the total for all this would be about £160! Thankfully I had a lot of this already anyway from other projects. I guess it shows that the Recon glasses are actually quite good value for the technology that you are getting and the functionality that it offers.

If I end up getting a pair of the proper Recon goggles I'll have a play with the SDK and see what else interesting could be done with a properly engineered product!

Oh, and #IfIHadGlass, I'd start with reimplementing this, before getting on to a load of other projects I'd like to try :)


Snowboard HUD Part 9 - Field Test 1

I'm going to take the glasses out today and try them outside with the battery pack. Before that I thought I'd make a quick summary of the setup and show all the components finally put together.



Below is a video showing all the wearable components in my jacket (sorry the video is a bit shaky).



The first video from inside the glasses is below. I'm not that happy with it really. I will try to make a better one when I get some time over the next couple of days.







Saturday, 23 March 2013

Snowboard HUD Part 6 - Auto-launching the script

Now that the battery pack has arrived I can now think about making this mobile.

Before I get on to connecting up the battery, I need to make the display script start up automatically, since when it is out and about it wont have a keyboard attached in order to load the script.

Running scripts on startup can be achieved in a number of ways. I wish I could find a decent article somewhere that descripbes all the different methods and why you might choose one over the other. I have in the past modified the .profile file within the user's home folder, but in this case I need to run scripts using sudo, and I haven't been able to do that using the .profile. Therefore what I've done is used the guide from here.  First I created a new file called rungui

sudo nano /etc/init.d/rungui

and put this text into it

#! /bin/sh
# /etc/init.d/rungui

### BEGIN INIT INFO
# Provides:          noip
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Simple script to start a program at boot
# Description:       A simple script which will start / stop a program a boot /$
### END INIT INFO

echo 'called rungui script'

sudo killall gpsd
sudo gpsd /dev/ttyUSB0 -F /va
sudo python /home/pi/test_gui3.py

exit 0

The important lines are at the bottom

The two lines that refer to gpsd have been added since for some reason my GPS has stopped working unless you do this on every boot. I have no idea why, I don't think I have changed anything since I first got this working, but eventually I found I could fix it with these two lines. So I'm calling them on every boot of the pi.

The script is then called suing python /home/pi/test_gui3.py. I should probably rename that something sensible at some point.

Once this file is created run:

sudo update-rc.d rungui defaults

and the script should be launched automatically when the pi boots.



Friday, 15 March 2013

Snowboard HUD Part 5 - GPS Integration

For the GPS integration, the articles from Kevin Townsend have been invaluable. The hardware I'm using is the Ultimate GPS Breakout Board. Mine was from Cool Components in the UK.



As per the suggestion in Kevin's article I'm also using a USB to serial converter rather than using the GPIO pins directly. I got this from Amazon UK (http://www.amazon.co.uk/gp/product/B008AGDTA4)

This worked just by plugging it into the Raspberry Pi and is accessible probably as:

/dev/ttyUSB0

The instructions on Kevin's page are really comprehensive so I wont repeat them here. The only mistake I made was in connecting the GPS breakout to the serial.

The coloured cables from the USB to serial are:

Red    VCC
Black    GND
Green    TXD
White    RXD

Everytime I do something with serial I do this wrong, and it is completely logical I just seem to do it wrong every time! The TXD from the USB to serial needs to connect to the RX on the GPS breakout. I've put a picture below. Sorry the cables for TX and RX are both yellow, it doesn't help with the understanding but it's all I had.



Once you get it all working, on the Raspberry Pi if you run

cgps -s

you should see output something like this:


However, what we really need is to be able to access this information from the Python program created earlier. In order to do this Kevin has another article with examples http://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi/using-your-gps

Based on these examples, my updated code is:


# coding=UTF-8

import pygame
import sys
import datetime
import gps

def draw_borders(screen):
    """Draws some simple borders to the display"""
    pygame.draw.lines(screen, (255, 255, 255), False, [(0, 30), (width, 30)], 2)

def draw_time(screen):
    """Draws the time to the display"""
    the_time = datetime.datetime.now()
    time_as_string = the_time.strftime('%H:%M')

    font = pygame.font.Font(None, 42)
    text = font.render(time_as_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()/2, centery=15)
    screen.blit(text, textpos)  # paste the text into the background

def draw_speed(screen, the_speed):
    """Draws the speed to the display"""

    # get the speed...
    if the_speed:
        the_speed_string = '{} kph'.format(int(the_speed)) # display as whole number
    else:
        the_speed_string = '-- kph'

    font = pygame.font.Font(None, 160)
    text = font.render(the_speed_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()/2, centery=screen.get_height()/2)
    screen.blit(text, textpos)  # paste the text into the background


def draw_altitude(screen, the_altitude):
    """Draws the altitude to the display"""
    if the_altitude:
        the_altitude_string = '{} m'.format(the_altitude)
    else:
        the_altitude_string = '-- m'

    font = pygame.font.Font(None, 65)
    text = font.render(the_altitude_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=120, centery=screen.get_height()-20)
    screen.blit(text, textpos)  # paste the text into the background


def draw_temp(screen):
    """Draws the temperature to the display"""
    the_temp = 0
    the_temp_string = u'{}°C'.format(the_temp)

    font = pygame.font.Font(None, 65)
    text = font.render(the_temp_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()-80, centery=screen.get_height()-20)
    screen.blit(text, textpos)  # paste the text into the background


if __name__ == '__main__':

    pygame.init()

    size = width, height = 650, 400
    black = 0, 0, 0

    screen = pygame.display.set_mode(size)

    # set up gps if possible
   
    gps_session = gps.gps("localhost", "2947")
    gps_session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

    speed = None
    altitude = None

    while True:
        # Checks for key presses, e.g. escape to quit
        for event in pygame.event.get():
            if event.type == pygame.QUIT: sys.exit()
            if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: sys.exit()

        # Fill the screen with black background
        screen.fill(black)

        # get GPS data
        gps_report = gps_session.next()
        altitude_temp = gps_report.get('alt')
        speed_temp = gps_report.get('speed')
        # need to do this temp stuff otherwise it flickers
        # back to '--' if gps is temporarily lost
        if altitude_temp:
           altitude = altitude_temp
        if speed_temp:
            speed = speed_temp

        # Draw all the stuff
        draw_borders(screen)
        draw_time(screen)
        draw_speed(screen, speed)
        draw_altitude(screen, altitude)
        draw_temp(screen)

        # Update the display
        pygame.display.flip()




And the output:




I haven't been able to test the speed yet until I get a battery pack, but you can see that the altitude has been updated.

It is also worth looking at the other details that are stored within the gps_report variable. The Python dictionary keys are in italics.

longitude     lon
latitude     lat
time     time
altitude     alt (m)
speed     speed (kph)
climb     climb (m/min)
heading     track (degrees) (I think)

Might be able to add more of this information in later.




Snowboard HUD Part 4 - Basic display

This posts describes the construction of a basic display with some placeholders.

The idea is to produce something like this that displays the speed, altitude and temperature.



I'm using a Raspberry Pi and I want to avoid booting into the GUI so I need a way of creating a graphical display from the terminal display. I discovered that this is possible using Python and PyGame.

I think this was already installed but in case it isn't, the easiest thing to do is use aptitide to install python setup tools and then you can install any packages you want.

sudo apt-get install python-setuptools
sudo apt-get install python-pip

then you can use pip to install other Python packages e.g. PySerial

sudo pip install pyserial

So to create the display I'm going to use PyGame. This may not be the most sensible thing to do, but it does seem to work. Alternative suggestions welcome.

I used a PyGame tutorial from Pete Shinners to get me started, which was very helpful.

This first version of the display creates some text in fixed positions in the display as placeholders until I can actually start reading some data. There are also a lot of hard coded positions , which at the moment doesn't matter because it is set up to be displayed on the MyVu glasses.



# coding=UTF-8

import pygame
import sys
import datetime


def draw_borders(screen):
    """Draws some simple borders to the display"""
    pygame.draw.lines(screen, (255, 255, 255), False, [(0, 30), (width, 30)], 2)

def draw_time(screen):
    """Draws the time to the display"""
    the_time = datetime.datetime.now()
    time_as_string = the_time.strftime('%H:%M')

    font = pygame.font.Font(None, 42)
    text = font.render(time_as_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()/2, centery=15)
    screen.blit(text, textpos)  # paste the text into the background

def draw_speed(screen):
    """Draws the speed to the display"""

    # get the speed...
    the_speed = 0.0
    the_speed_string = '{} mph'.format(int(the_speed)) # display as whole number

    font = pygame.font.Font(None, 160)
    text = font.render(the_speed_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()/2, centery=screen.get_height()/2)
    screen.blit(text, textpos)  # paste the text into the background


def draw_altitude(screen):
    """Draws the altitude to the display"""
    the_altitude = 0
    the_altitude_string = '{} m'.format(the_altitude)

    font = pygame.font.Font(None, 65)
    text = font.render(the_altitude_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=120, centery=screen.get_height()-20)
    screen.blit(text, textpos)  # paste the text into the background


def draw_temp(screen):
    """Draws the temperature to the display"""
    the_temp = 0
    the_temp_string = u'{}°C'.format(the_temp)

    font = pygame.font.Font(None, 65)
    text = font.render(the_temp_string, 1, (255, 255, 255))
    textpos = text.get_rect(centerx=screen.get_width()-80, centery=screen.get_height()-20)
    screen.blit(text, textpos)  # paste the text into the background


if __name__ == '__main__':

    pygame.init()

    size = width, height = 650, 400
    black = 0, 0, 0

    screen = pygame.display.set_mode(size)

    while True:
        # Checks for key presses, e.g. escape to quit
        for event in pygame.event.get():
            if event.type == pygame.QUIT: sys.exit()
            if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: sys.exit()

        # Fill the screen with black background
        screen.fill(black)

        # Draw all the stuff
        draw_borders(screen)
        draw_time(screen)
        draw_speed(screen)
        draw_altitude(screen)
        draw_temp(screen)

        # Update the display
        pygame.display.flip()




And what this produces is:


You can see that this is actually being run on a Mac, which is good for editing the display layout, maybe doing some keyboard based control later, but the actual display needs to run on the Pi connected to the glasses.

You can see the same here being displayed in the glasses.




As a side note, I'm actually getting the code onto the Pi by copying it to a public dropbox folder and downloading with wget. I'm doing a lot of this through SSH-ing into the Pi, but I don't know how to start the script from the remote login and have the display update on the glasses that are connected via composite. Please let me know if you know if this is possible. You can just about hear from the video that I have a keyboard connected the the Pi in order to run the Python script.

I also had to mess around quite a lot with the resolution of the display. If the MyVu didn't like the resolution I would get a blank screen inside the glasses and couldn't get rid of it without restarting the Pi. The line configuring the PyGame display:

size = width, height = 650, 400

isn't the maximum resolution that I could probably use, but it does work.