Tags

, , , , , , , , ,

To recap. Arkwood asked me to write some code, so that Google Street View could be controlled simply by speaking into a microphone. It was a tall order, but one which I achieved by using Google’s Speech To Text service to convert his voice commands into text that the Python program could understand. I posted my triumphs in Using voice to control Google Street View and Using voice to control Google Street View (Mark II).

‘But you don’t understand,’ said my creepy Belgian friend, ‘I prefer walking the streets aimlessly until I find something that titillates me. Then I like to replay the experience in my mind.’ I must say, his words left me feeling dirty, but not wanting to disappoint him I began cutting some code to meet his sordid requirements.

First, we need a program that will store random commands:

from constants import FORWARD, BACKWARD, LEFT, RIGHT
import random
from storage import Storage
from time import sleep

storage = Storage()

# set up weighted commands
commands = [FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, 
              FORWARD, FORWARD, FORWARD, FORWARD, FORWARD, BACKWARD, LEFT, RIGHT]

#loop forever
while True:

    # get random command
    command = random.choice(commands)

    # store command
    storage.write_value("streetview.conf", command)

    # pause
    sleep(10)

As you can see, we opt for far more FORWARD commands than BACKWARD, LEFT or RIGHT. Otherwise we will simply be going round in circles. Python has a neat random.choice() function, which selects the next command to store. Our commands are referenced from a constants file (along with a few other constants which we’ll use later):

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

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

Now we need another program to pick up these random commands from storage and render them in a browser:

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

storage = Storage()
nomad = Nomad(22.278142, 114.172798, EAST)

#loop forever
while True:

    # pause
    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())

    # store url for possible replay
    storage.write_value("streetview_replay.conf", url)

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

A couple of things to note here. Once we read the latest command from file, we use our Nomad class to process it and supply the web browser with a Google Street View url. We also store each url we handle, so that we can replay our journey at a later date, just as Arkwood requested.

Here’s the Nomad class, which keeps track of where we are in Google Street View:

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

And here’s the replay program, which we can use at a later date to repeat each of Arkwood’s predatory steps:

from storage import Storage
import webbrowser
from time import sleep

storage = Storage()

# retrieve all urls to replay
urls = storage.read_all_values("streetview_replay.conf")

#loop urls
for url in urls:

    # open web browser with next url
    webbrowser.open(url)    
    
    # pause
    sleep(10)

Grand. For the sake of completeness, here’s the code that takes care of our storage requirements:

class Storage(object):

    # write to file
    def write_value(self, filename, value):
        try:
            with open(filename, "a") as value_file:
                value_file.write(value.strip() + '\n')
        except:
            print ("Error writing value")

    # read last value from file
    def read_last_value(self, filename):
        try:
            with open(filename) as value_file:
                lines = value_file.readlines()
                return lines[-1].strip()
        except:
            print ("Error reading last value")

    # read all values from file
    def read_all_values(self, filename):
        try:
            with open(filename) as value_file:
                lines = value_file.readlines()
                return lines
        except:
            print ("Error reading all values")

It’s worth noting that using Python Tools for Visual Studio makes it dead simple to write, debug and execute all this code.

So that’s quite a lot to take in. Let’s have some screenshots! So we use the stored urls to replay a random stroll through Google Street View (in this example, we finish our journey by ramming into some shops):

https://maps.google.com/?layer=c&cbll=22.278142,114.173398&cbp=12,90,0,0,0
streetview_hk_replay_1

https://maps.google.com/?layer=c&cbll=22.278142,114.173398&cbp=12,180,0,0,0
streetview_hk_replay_2

https://maps.google.com/?layer=c&cbll=22.277942,114.173398&cbp=12,180,0,0,0
streetview_hk_replay_3

But the big question is, What does Arkwood think? ‘Nice. I spy me some pretty ladies, woof woof!’ he screamed. Oh, it’s enough to make you shiver.

Ciao!