Tags

, , , , , , , , , , , , ,

Okay. So Arkwood has been badgering me something rotten to improve on the Python code I wrote, to control Google Street View with nothing but the sound of his voice.

In the last post we were able to speak into the microphone attached to our Raspberry Pi and convert our voice commands into text using Google’s speech to text service. Once we had stored our commands in a text file, our Windows PC was able to collect them over the network and launch a web browser tab, displaying Google Street View just the way we asked it to. That was great, but we only had it walking up and down a single street, or rotating left and right. What we really want is for it to take a stroll through town. Well, read on…

I write my Python code in Python Tools for Visual Studio, which you can get your hands on for free. I really can’t stress how great this software development environment is, allowing for a top debugging and IntelliSense experience in which to iron out all your coding mishaps. My code revisions focussed solely on navigating Google Street View, as the voice command stuff on the Raspberry Pi was already working well.

So, here’s the Nomad class (named after a person on the move, get it?), that will take care of said navigation:

from constants import *

class Nomad(object):

    # class constants
    COMPASS = [NORTH, EAST, SOUTH, WEST]
    STEP = 0.000200

    # initialise
    def __init__(self, latitude, longitude, needle):
        if needle not in self.COMPASS:
            raise Exception("Needle is guff")
        
        self.latitude = latitude
        self.longitude = longitude
        self._index = self.COMPASS.index(needle)

    # get needle
    def needle(self):
        return self.COMPASS[self._index]

    # rotate the body left
    def _rotate_left(self):
        self._index -= 1
        
        if self._index < 0:
            self._index = len(self.COMPASS) - 1

    # rotate the body right
    def _rotate_right(self):
        self._index += 1
        
        if self._index > len(self.COMPASS) - 1:
            self._index = 0

    # take a step forward
    def _step_forward(self):
        if self.COMPASS[self._index] == NORTH:
            self.latitude += self.STEP

        elif self.COMPASS[self._index] == EAST:
            self.longitude += self.STEP 
               
        elif self.COMPASS[self._index] == SOUTH:
            self.latitude -= self.STEP 
                      
        elif self.COMPASS[self._index] == WEST:
            self.longitude -= self.STEP 

    # take a step backward
    def _step_backward(self):
        if self.COMPASS[self._index] == NORTH:
            self.latitude -= self.STEP
        
        elif self.COMPASS[self._index] == EAST:
            self.longitude -= self.STEP    
        
        elif self.COMPASS[self._index] == SOUTH:
            self.latitude += self.STEP           
       
        elif self.COMPASS[self._index] == WEST:
            self.longitude += self.STEP 

    # try moving the nomad
    def move(self, command):
        if command == LEFT:
            self._rotate_left()
            return True

        if command == RIGHT:
            self._rotate_right()
            return True

        if command == FORWARD:
            self._step_forward()
            return True

        if command == BACKWARD:
            self._step_backward()
            return True
          
        return False

When we initialise the class, we let it know our latitude and longitude, as well as the needle position on the compass i.e. are we facing North, East, South or West. After that, we can simply call the class’ one public function Move, which will inspect the command passed to it and decide whether the Nomad should move forward, backward or rotate left or right. That’s it really, the rest of the gubbins are just concerned with keeping the Nomad on track.

Now let’s look at the main program:

from constants import *
from storage import Storage
from nomad import Nomad
from time import sleep
import webbrowser

storage = Storage()
nomad = Nomad(22.294612, 114.172113, WEST)

#loop forever
while True:

    # WARNING! make sure you sleep or your computer will open
    # an insane amount of browsers and crash (my God, I know)
    sleep(10)

    # retrieve most recent command
    command = storage.read_last_value("streetview.conf")

    # if command not valid then avoid launching browser
    if command not in (FORWARD, BACKWARD, LEFT, RIGHT):
        continue

    # update nomad with command
    nomad.move(command)

    # update url with new parameters
    url = "https://maps.google.com/?layer=c&cbll={},{}&cbp=12,{},0,0,0".format(nomad.latitude, nomad.longitude, nomad.needle())

    # open web browser with url
    webbrowser.open(url)

We’re grabbing the latest voice command from a text file (the very file that the Raspberry Pi is writing to) and updating the Nomad accordingly. Now we can use the updated Nomad to populate the Google Street View url, before launching a browser tab.

Oh, and here is the constants file, which we make use of in the main program and the Nomad class:

# command constants
FORWARD = "forward"
BACKWARD = "backward"
LEFT = "left"
RIGHT = "right"

# needle constants
NORTH = 0
EAST = 90
SOUTH = 180
WEST = 270

Arkwood has told me that if I don’t provide a demo he will urinate in my plant pots again, so here goes with a stroll through Hong Kong…

We add the voice command ‘forward’ to our text file, and the program picks this up and moves us down the street:

forward

streetview_hk_1
streetview_hk_2

Now we update our text file with command ‘right’ and we turn to face a new street:

forward
right

streetview_hk_3

If we then update the file with ‘forward’ again, we will begin to walk down this new street:

forward
right
forward

streetview_hk_4

Of course, we can also turn ‘left’, turn ‘left’ twice so we face from whence we came, or simply walk ‘backward’ so we are literally stepping back whilst still facing ahead. Fantastic! I am using nothing but my voice to navigate through the dirty rickshaw-ways of the former British colony.

Now, getting this working within the same browser tab may require a tweek to the browser settings. For example, in Internet Explorer 11 go to Tools-Internet Options-General-Tabs-Open links from other programs in-The current tab or window. No more worries about lengthy demos opening new tabs and eating up the computer’s memory.

streetview_tabbedbrowsingsettings

So I have achieved my objective, which was to afford my horny Belgian friend the chance to snoop about the dwellings of beautiful girls without the use of his hands. Anything to stop him pissing in my pots would be a step forward for me.

Ciao!