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

  1. Another fun Posie adventure (Rosie Mind Meld) - thanks. There is so much to investigate, and so many ways to do things, that learning from other robots is the only way my bot "grows up".

    For some reason, I had to browse to the stylesheet to get it to update after changes, but I got it all to work well, and pretty, in the end.

    Posie nearly went berserk once, bogged down with repeated alerts and web commands. (I have several other threads going, including another thread reading the ultrasonic sensor. )

    I added time limits to the control commands since Posie can only "see" forward, and the bump direction sensors are not integrated into my simulated rrb3 motors API.

    Thank you. Thank You! THANK YOU.

    ReplyDelete

Post a Comment

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…

Break an egg! You've got to be in it to win it.

What the 'egg? It turns out: parenting is actually quite hard.

Not least because you suddenly find yourself responsible for one, two, or - in our household - three little miniature versions of us that need to be kept well away from the soldering iron. Or the 3D printer. Or that marauding hexapod that you forgot to power off before you left for work in a hurry.  But to compound matters further, you find yourself well and truly ambushed - financially.  You are at all times being pressurised by dark forces beyond your control to make an investment, however dubious the return.

That's right.  Clearly, you will be considered an abject failure as a responsible adult if you don't purchase the latest, trendy parenting gizmo. That feeding bottle sterilising kit clinically proven to kill all known bacteria through the science of nuclear fission. Or that titanium alloy buggy guaranteed not to crumple in the event of a sudden collision with falling Soviet-era space debris.  Evidently,…

Raspberry bye, hello

Let us make this very clear from the onset of this exotic excursion.

This is not a case of Raspberry Bye. Our relationship with our favourite single-board computer hasn't at all soured. In fact, we've become wholly inseparable. There's been many months of undeniable fun that's been had with the venerable computer strangely named after an edible fruit. To the extent that our relationship requires a healthy break. And quite frankly, our Pis require a well earned summer holiday to do whatever it is that robots and computers do during their time off. Crash. Burn. Refuel (with questionable toxins). Not at all unlike their human counterparts. And ultimately, it would be nice if they could return to a brand new, adorable pet waiting for them at home, a likeable little companion that they can just get along with.

Well, we visited a pet shop, but couldn't find anything as small and smart as this adorable pup we stumbled up on while searching the Internet for a new, miniat…