Skip to main content

A web of Pies


Have you given this a proper thought?  How will your Grandma - Nancy - move Rosie around the house to transport her dentures.  Just like we've been doing, of course, using a computer with a SSH client, logging onto Linux (Raspbian OS) remotely, and running Python commands from the Linux shell.  Easy-peasy.  Why would you even ask that?

'What?!' you hear her shout.  'I'll never do that,' she adds.  'Me and my friends play online bingo using Firefox on our nursing home computers.  I use Skype on my Android tablet to talk to grandchildren that I never knew I had.  Didn't you know?  It's all about HTTP and web-based services these days?  I want to be able to get my dentures, anywhere, anytime, from any device... with a few taps of the screen.  I demand Rosie-as-a-Service!'

Deep down, you know she's right.  Nancy, your irritating littler brother, your friends - they are never going to be able to play with Rosie if she stays like this.  Besides, we don't want any of those people actually logging into Rosie's brain, and breaking things.  They type 'rm my_important_script.py', instead of 'python my_important_script.py' (as you told them to, literally, millions of times), and suddenly your masterpiece is gone, forever.

The solution?  Let's convert our program into a little web application, and instead of using arrow keys on the keyboard, allow Rosie's movements to be controlled remotely using the magic of HTTP.  All using an appallingly bad easy to use web page showing only the buttons Grandma actually needs.

Denture-Express 2000, here we come!

You will need to have these:

  • Raspberry Pi 3 (kitted out with wheels and sensors), and Raspbian running on SDHC card
  • Computer from which you are connecting to the Raspberry Pi remotely
  • Other devices on your home network from which you would like to control Rosie. They need to have a browser installed, like Chrome, Safari, Firefox, Internet Explorer, Edge, etc, etc.

You will need to have done these things:

  1. I’ve got Pi(3) brain
  2. Why-Fi-ght the Wi-Fi?
  3. Hurrah-ndom inventions
  4. Don't reinvent the eel
  5. Achoo! Crash-choo! Episode I
  6. Achoo! Crash-choo! Episode II

You will need to do this:

  • Install Flask using Pip 
  • Modify code to use Flask and handle HTTP
  • Create a HTML template and a CSS stylesheet
  • Start application and control Rosie using your favourite device

What do you get after all this?

Let's get this concern out of the way first: we're not making Rosie available on the Internet. That would be pretty unwise, you know, with all 'em hackers around the world, waiting to hack your Internet-connected vacuum cleaner, intelli-fridge and electronic toothbrush that brushes your teeth while you're sleeping. We will be turning the code we've written into a little web application, but it will only be reachable on your home network. On the other hand, it does mean that your family and friends (when visiting) will be able to control Rosie if they know her web address. Well, that was the whole point of this exercise wasn't it?

Here are the various technologies at play.  Hypertext Transfer Protocol (HTTP) is a Protocol used pretty much everywhere on the Internet. It's the reason why when you enter http or https in a web browser, followed by an address of a web site, things are helpfully returned to your screen.  Essentially, HTTP allows the user (also called client) and application (also called server) to communicate in an agreed language (protocol), using known rules, and pass information back and forth. All, over a network.  That's right; you can thank HTTP for your daily dose of cat falling off bicycle videos, and for allowing you to Google pretty much anything that you don't know, and then afterwards, pretend that you do. This client-to-server model, using HTTP, is used extensively for machine to machine communication as well, in the form of Application Programming Interfaces (APIs).  It's something that will definitely be useful, when we eventually want Rosie-01 to talk to Rosie-02.

But hold your horses. Let's get you talking to Rosie first, using HTTP. And implement the web page that Grandma Nancy wants to use to get Rosie to deliver her trusted prosthetic teeth.

But here's another fact.  You could spend all year coding a website from scratch. Writing hundreds of pages in Hypertext Markup Language (HTML), a language used to build the structure of web pages (what you see on screen), or Cascading Style Sheets (CSS), which is a different language used to make those pages look pretty.  Or, even, writing actual application code itself that - probably - a million others would need to be writing as well.  After all, everyone wants to do something with the web.  And chances are, someone has already helpfully come up with all the building blocks that you need.

That's why most people use Frameworks. Because with frameworks, someone else has already thought about all the basic components that you need to build a web application, and agreed on a standard, documented it, and made it available for everyone else to use and improve. Frameworks allow you to concentrate on the bits of your application that matters the most, functionality, and allows you to (mostly) forget about the boring bits that everyone needs.

If sticking with Python, Flask and Django are two of the more popular web Frameworks. Flask is very simple, lightweight, and a doddle to get working. Django is arguably more difficult to learn, and is a little more complex, large, but more powerful.  We think for what we want to be able to do here (a single web page with control buttons), Flask is good enough.

And oh yes, the result won't look super pretty; like a web page that has been written by a colour-blind monkey who has had one too many piƱa coladas. But who cares if it means that Grandma will be able to get her dentures, using her iPhone, from the comfort of her own sofa.  And by using HTML and CSS, it can be tweaked/prettified/improved/fixed easily, to your heart's content.

This is simply too much detail:

So Flask, you say. Do we have that already? Probably not... so we'll have to check. What do we need to have to check to see if we have Flask? We need Pip. Aargh. Can we just get on with it please?

Pip is a Python package manager, which - in simple terms - allows you to install and manage Python software.  If you want to make use of a lot of great things that cleverer people have done with Python (like a web framework), and you intend to download and use them in your projects, it's best to let Pip manage those packages for you.  Some packages are dependent on other packages, and even in some cases, certain versions of those packages.  Keeping track of all of this simply shouldn't be a human task.

Pip was already on our version of Linux (Raspbian OS).  Check that it exists, by running:

pip --version
...checks version of Pip installed
 

One down, another to go.  Let's now check to see if we have the Flask package, again, using Pip.
pip list
...lists all installed Python packages

No Flask?  Plenty of other things there though.  Well, let's install it.  If you already had it, it would have appeared in the list like this:


Before we proceed, it's worth remembering (for the future) that on computers where we have many Python projects on the go, we are likely to want to have different versions of the same Python packages installed.  We might even need to maintain different versions of Python itself.  There are packages that allow you to do just that - such as virtenv or virtualenvwrapper.  For now, we are going to proceed without them as we're feeling... not very ambitious.

 
We're going to build a very primitive web application.  It won't have any form of authentication, and therefore anyone who can reach her on your local network will be able to control Rosie, remotely, using the buttons.

Let's install Flask.

pip install Flask
...downloads and installs the Flask package.  Make sure your Pi has an Internet connection beforehand!

 
Once complete, run 'pip list' again to make sure you have successfully installed Flask.  There?  Good.  We're ready to go.  Let's create a new directory in which to store our web application, and create a Python file in it, aptly named 'rosie-web.py'.  Because it'll be a web application, get it?

cd /home/pi/rosie
mkdir rosie-web
cd rosie-web
touch rosie-web.py

We'll be needing two additional directories in which Flask will look for some files, so let's create them now before we forget.

mkdir templates
mkdir static

'Templates' will contain HTML files that define how our web pages are structured.  'Static' will contain the CSS files that define how those pages look in your browser (like fonts, colours, sizes of buttons, and stuff).

We're ready to now populate 'rosie-web.py' with our code, and make use of Flask.  Here is the simple code that we eventually settled on.

First of all, we stripped out all of the keyboard related code that we had before in 'rosie_wheels_with_distance.py'.  It's no longer needed.  We're going all out web.  In its place, however, are a number of new Flask-related additions.

Like with any other module, before we do anything with it, we need to import Flask, and the functions that we'll be using.

from flask import Flask, render_template, request, url_for, redirect

We then create an instance of our Flask application.  This is the Python code to do just that.

app = Flask(__name__)

We've decided to have two Flask-related functions that handle requests from the HTTP client (in our example, Nancy's browser).  We know they are Flask functions, as we have a decorator at the start - @app.route().  This effectively tells the code that if any HTTP requests arrive at that web address, trigger the function that follows.

First of the two functions is for root (/).  If users land at the root (/) of our site (for example http://rosie-01:5000/), they will simply be shown an 'index' page (index.html).  This index page will just contain the buttons needed to move Rosie.  You know, the kind of buttons that you need to press on a train company website when you want to submit a complaint about your train being late (again).

@app.route("/")
def index():
    return render_template("index.html")

The second of our Flask functions will be used to define what happens when the buttons are pressed in index.html.  The browser will submit a value using what's known as a 'POST' request.  This value will be the direction in which Rosie is expected to move.  When we receive that value (at /control address, for example http://rosie-01:5000/control), we read it, then step through the same Python code that we used when reacting to keyboard arrow keys.  The final action in this function (return redirect(url_for())) is to simply redirect the user's browser back to the index.html page.  This isn't the most elegant of solutions, as the web page is refreshing every time you are sending a command... but it's crude and simple.

@app.route("/control", methods = ["POST"])
def control_rosie():
    control = request.form.get('control')
    if control == "Forward":
        #...code to move motors
        #...repeat for other directions
    return redirect(url_for("index")) 

Lastly, in the main section of the program, we will start the Flask web application.

app.run(host = "0.0.0.0")

This starts a built-in 'development' web server (included with Flask), which then allows users to access the application over the network, see our wonderful index.html page, and start submitting HTTP requests.  Remember that this is a development server.  If you want to sell Denture-Express 2000 on Amazon, or make it available to millions of people over the Internet, you will want to run the same Flask code, but on a more 'production-ready' web server, like Apache HTTPD, or nginx.  Great.  More strange words to Google!

Now, there are two non-Python things left for us to complete.  We need to create the 'index.html' file, so that we have a page that can be displayed in the browser.  This file is expected in the 'templates' directory created earlier.

cd templates
touch index.html

The HTML code we've used is shown below.  In short, we have a form, which contains a number of buttons arranged in a table.  Each button corresponds to a direction for Rosie.  When the button is pressed, its value is submitted to the '/control' address, and is therefore handled by @app.route("/control", methods = ["POST"]) we defined for Flask earlier.  This, of course, means that Rosie moves, just like it did when we were pressing keyboard keys.

<html>
    <head>
        <link rel="stylesheet" href="/static/style.css" />
    </head>
    <body>
        <h1>Welcome to Rosie's controls</h1>
        <form action="/control" method="post">
            <table border=0>
                <tr>
                    <td></td>
                    <td><button class="button-control" type="submit" name="control" value="Forward">&uarr;Forward</button></td>
                    <td></td>
                </tr>
                <tr>
                    <td><button class="button-control" type="submit" name="control" value="Left">&larr;Left</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Stop">Stop</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Right">Right&rarr;</button></td>
                </tr>
                <tr>
                    <td></td>
                    <td><button class="button-control" type="submit" name="control" value="Reverse">&darr;Reverse</button></td>
                    <td></td>
                </tr>
            </table>
        </form>
    </body>
</html>

HTML is used with all web technologies, Python or not, so its strange way of describing a web page's structure and content is well worth learning.  

Finally, create a CSS file called 'style.css' in the 'static' folder.  This file was referenced in the <head> tag of the index.html file.  Cascading Style Sheets (CSS) allow HTML files to be visually presented in the way that you want.  This is where you can be creative, and spend many hours applying different colours, fonts, effects, etc to your web page.

cd ../static/
touch style.css

For now, we are going to apply a splash of colour to the background of the page, and change the colour of the font.  We will also make the buttons square, large and colourful (remember, this is for Grandma?)

body {
 background: #ff4141;
 color: #532619;
}

.button-control {
 height: 100px;
 width: 100px;
 background: #eec6c6;
 color: #532619;
 border-radius: 5px;
}

.button-control:active {
 color: #eec6c6;
 background: #532619;
} 

Finally, the moment of truth.  Let's start our application.

cd /home/pi/rosie/rosie-web
python rosie-web.py


Now, from a browser on another device on your home network, navigate to address 'http://rosie-01:5000'.  You should be presented with your HTML page, styled using your CSS.  And when you press the buttons, your POST HTTP requests will be fired at your Flask functions, which will (hopefully) move Rosie around as expected.


It's extremely primitive, and it's totally not fit for purpose.  After all, where is the login page?  Why can't we see some of Rosie's messages on the page?  What happens if we lose connection to Rosie, even momentarily?  Of course, there's plenty of ways in which it can be improved. But, all things considered, we have achieved quite a lot with the help of Flask.  Rosie is web-enabled, and this will keep Grandma Nancy happy (for a little while).

Even more reading:

Official Flask documentation can be found here:

Comments

Popular posts from this blog

Tea minus 30

We're fast approaching Christmas time.  And if robots were to make one simple observation about the human species during the Christmas festivities, it's that they watch a lot of TV.  A LOT.  Often, accompanied by an inappropriate amount of greenhouse gas-producing food.  Stuff you don't normally eat during the remainder of the year - for good reason.

And most so-called shows on TV are boring to robots like Rosie.  After all, why watch a minor subspecies of the human race - celebrities - stumble awkwardly around the dance floor, dressed like a faulty, sparking circuit board?  Such branch of entertainment doesn't require robots to engage any of their proud circuitry.  Their processors remain idle.  Memory under-utilised.

But if robots are to be part of people's homes (and blend in), they need to look at least a little interested in some of this irrational nonsense.  Nobody likes a party pooper.  A killjoy.  And this is where a certain subgenre of TV entertainment co…

Beam me up, Rosie!

How do you get from A to B?

You can't, as As and Bs are just letters in the alphabet. But if A is your house, and B is a meerkat village at your favourite safari park, you'd probably use a device equipped with GPS.  Not to be confused with UPS, who will deliver you your chosen meerkat through the post. And why on Earth would Rosie Patrol need one? Precisely, it's because she is on Earth that she needs one. Because our planet is rather big. Big enough to get lost in. And we don't want to lose our friendly plastic boxes on wheels. And maybe, eventually when she's clever enough, she'll go and defeat baddies on her own. And return home afterwards for a well deserved Earl Grey tea.

Besides, why wouldn't we want to add another three letter acronym to Rosie Patrol's repertoire?
All superheroes need:One Raspberry Pi 3, running Raspbian OSComputer from which you are connecting to the Raspberry Pi Probably the most important bit: a GPS receiver thingmy. …

Hello supervision, goodbye supervision

The time has finally come, to let our precious Rosie go.  Wish her luck (yes, she'll really need it).  Press the big red button.  And watch her destroy / navigate (delete as appropriate) the terrain*.  All on her own.  Without your help.  Well, sort of.

*Somewhat scientific term... for your lounge

You see, cool robots are never meant to be controlled by us clumsy humans.  If they want to be clumsy, they can be clumsy on their own.  That way we can deny all responsibility when they crash into the neighbour's car.  Or, less importantly, take over the world.

And by the way, Autonomous stuff seems to be in fashion these days.  Self-driving cars are just around the corner (maybe quite literally).  Very clever computers also beat humans at chess, apparently.  After all, if robots only do what we tell them to do, they are going to need us.  They're going to be just like us.  Oh no.  We want them to work alongside us, to do things that we simply can't be bothered to do.  Like …