There are a lot of Python web library choices, with each of the libraries offering different features and functions.
For simple Raspberry Pi Web application I was really impressed by the Python Bottle library. In this blog I’d like to document a Raspberry Pi rover project that I did using bottle.
Getting Started
To install the Python bottle library:
pip install bottle
There are some good tutorials for bottle. Probably the most important item is defining a decorator for a URL, and then linking the decorator to a function:
@route('/') # define a decorator for the start page def my_homefuntion() # call a function for the start page return static_file("startpage.htm", root='') # call the start page @route('/otherpage') # define a decorator for another page def my_otherpage_function() # call a function for the start page # do some stuff...
For the RaspPi rover I used a low cost car chassis (~$15).
It is not recommended to connect motors directly to Rasp Pi pin, for a few reasons:
- larger motors require more power that a Pi GPIO pin can supply
- power surges on motors can damage the Pi hardware
- forward/backward motor directions require extra hardware
- GPIO pins will only do ON/OFF, no variable speed settings.
There are a number of Raspberry Pi motor shield that can be used. For this project I used the Pimoroni Explorerhat Pro ($23). The Explorerhat has an excellent Python library that allows you to easily control the motor’s direction and speed.
Web Page
The goal for the web page (bottle1.htm) was to have 5 buttons for the controls and use AJAX to send the action request and then return the action code and display it on the page. The returned action would appear above the buttons ( in the lastcmd paragraph tag).
For this example the button push was sent in the header as a GET request. So a forward button push would be a myaction: forward header item. In previous projects I’ve used POST request with parameters, however I found that header items can make things a little simpler.
<!DOCTYPE html> <html> <head> <title>Python Bottle Rover</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <style> html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;} h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;} .button{display: inline-block; background-color: #4286f4; border-radius: 4px; color: white; font-size: 30px; width:100%; height: 75px} .button2{background-color: green ;width:31%} .stop{background-color: red; width:33%} </style> </head> <script> function sendcmd(thecmd) { // send the action as a header item var xhttp = new XMLHttpRequest(); xhttp.open("GET","/action" , true); xhttp.setRequestHeader("myaction", thecmd); xhttp.send() xhttp.onreadystatechange = function() { // Get the response and put on it the screen if (this.readyState == 4 ) { document.getElementById("lastcmd").innerHTML = "Last Command:<b>" +xhttp.responseText; } } } </script> <body> <h2>Python Bottle Rover</h2> <p id='lastcmd'></p> <button onclick="sendcmd('forward')" class="button">FORWARD</button> <button onclick="sendcmd('left')" class="button button2">LEFT</button> <button onclick="sendcmd('stop')" class="button stop">STOP</button> <button onclick="sendcmd('right')" class="button button2" >RIGHT</button> <button onclick="sendcmd('backward')" class="button button">BACKWARD</button> </body> </html>
Bottle Rover App
For the rover app, there are two URL endpoints. The root (/) which would display the bottle1.htm page, and an action (/action) URL which would only be called from AJAX script when a button was pushed.
For this project the Raspberry Pi ip address was hardcoded into the code, for future projects dynamically getting the ip would be recommend. Also a web port of 8000 was used so as to not conflict with a dedicated web server (like Apache) that could be running on the Pi.
# Bottle2rover.py - web control for a RaspPi rover<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span> # from bottle import route, run, static_file, request # Define RaspPi I/O pins import explorerhat # Send Action to Control Rover def rover(action): if action == "forward": explorerhat.motor.one.speed(100) explorerhat.motor.two.speed(100) if action == "left": explorerhat.motor.one.speed(100) explorerhat.motor.two.speed(0) if action == "right": explorerhat.motor.one.speed(0) explorerhat.motor.two.speed(100) if action == "stop": explorerhat.motor.one.speed(0) explorerhat.motor.two.speed(0) if action == "backward": explorerhat.motor.one.speed(-50) explorerhat.motor.two.speed(-50) # use decorators to link the function to a url @route('/') def server_static(): return static_file("bottle1.htm", root='') # Process an AJAX GET request, pass the action to the rocket launcher code @route('/action') def get_action(): action = request.headers.get('myaction') print("Requested action: " + action) rover(action) return request.headers.get('myaction') # Adjust to your required IP and port number run(host = '192.168.0.106', port=8000, debug=False)
Final Comments
I was happily surprised how easy it was to get a Python bottle web app running. The bottle documentation was straightforward and I found that the code was quite lean.