This is the beginning of what I expect to become a bit of a larger story: My little robot needs some kind of UI. First and most obviously, because it is supposed to create kind of a map, and I need to display that map somehow. But also, because I will probably need a bunch of additional controls: sensors and motors will need calibration, and I might want to build some manual controls for steering. As mentioned this is going to be a somewhat larger story, and this is why:
The map will not be there all at once. Instead, it will build up gradually as the robot is moving about. I will want both the robot's location (and orientation) as well as the map in progress to be updated continuously. So I guess a little Java-Script coding will be in order, in addition to some server-side code that will export a simple http service. But so far, we are not there yet. Instead, I built a very primitive piece of server code that looks vaguely like this:
RoboRequestHandler - A simple web UI for our Robot
This UI implements simple http and some dynamic content
such as a map and a json protocol for status information
'''
class RoboRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == "/":
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
elif self.path == "/dyn/map.jpg":
self.handle_dyn_map()
else:
self.send_response(403)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write("<html><head><title>403 Forbidden.</title></head>")
self.wfile.write("<body>403 Forbidden.</body></html>")
def handle_dyn_map(self):
self.send_response(200)
self.send_header("Content-type", "image/jpeg")
self.end_headers()
i = Image.new("1", (320, 200), color="white")
draw = ImageDraw.Draw(i)
draw.ellipse((0,0,319,199), outline="black")
i.save(self.wfile, format="JPEG")
# Start a web server and return
def start():
# Listen on standard http port to test privileges
PORT = 80
Handler = RoboRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "http serving at port", PORT
thread.start_new_thread(httpd.serve_forever, ())
I use Python's SimpleHttpRequestHandler as a basis for a custom RoboRequestHandler. The reason for doing so is because this way I can easily serve static content by delegating to the base class (it wouldn't be much of a big deal in either case, I know. But why repeat code that's already there?) It seems like a good idea to not give people access to all the files in the robot's software working directory, so we return a 403 response for everything we don't want people to see. We will happily serve an index.html file located in our working directory, though. And contained in that is an image, dynamically generated by the handle_dyn_map method and served as "/dyn/map.jpg". This is all a bit static for now, but I guess you can see where this will be going:
Don't blame me for having come up with the most ugly html page ever. I promise to keep improving on it ;-)
The map will not be there all at once. Instead, it will build up gradually as the robot is moving about. I will want both the robot's location (and orientation) as well as the map in progress to be updated continuously. So I guess a little Java-Script coding will be in order, in addition to some server-side code that will export a simple http service. But so far, we are not there yet. Instead, I built a very primitive piece of server code that looks vaguely like this:
RoboRequestHandler - A simple web UI for our Robot
This UI implements simple http and some dynamic content
such as a map and a json protocol for status information
'''
class RoboRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == "/":
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
elif self.path == "/dyn/map.jpg":
self.handle_dyn_map()
else:
self.send_response(403)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write("<html><head><title>403 Forbidden.</title></head>")
self.wfile.write("<body>403 Forbidden.</body></html>")
def handle_dyn_map(self):
self.send_response(200)
self.send_header("Content-type", "image/jpeg")
self.end_headers()
i = Image.new("1", (320, 200), color="white")
draw = ImageDraw.Draw(i)
draw.ellipse((0,0,319,199), outline="black")
i.save(self.wfile, format="JPEG")
# Start a web server and return
def start():
# Listen on standard http port to test privileges
PORT = 80
Handler = RoboRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "http serving at port", PORT
thread.start_new_thread(httpd.serve_forever, ())
I use Python's SimpleHttpRequestHandler as a basis for a custom RoboRequestHandler. The reason for doing so is because this way I can easily serve static content by delegating to the base class (it wouldn't be much of a big deal in either case, I know. But why repeat code that's already there?) It seems like a good idea to not give people access to all the files in the robot's software working directory, so we return a 403 response for everything we don't want people to see. We will happily serve an index.html file located in our working directory, though. And contained in that is an image, dynamically generated by the handle_dyn_map method and served as "/dyn/map.jpg". This is all a bit static for now, but I guess you can see where this will be going:
Don't blame me for having come up with the most ugly html page ever. I promise to keep improving on it ;-)
















