Using XML RPC to control your GoPiGo
GoPiGo is a really nice robot that you can build by your own. It’s inexpensive and a good starting point when learning robotics. First you need to assemble it by your own and install Raspbian for robots (a modified version of Raspbian OS for GoPiGo). With a help of step-by-step instructions it would be an easy deal. Once assembled you can use Python to program it. Usually you need to be remotely logged in and launch your script from remote terminal, so in this article we’ll be exploring another approach using remote procedure call. Thankfully Python has its builtin module for that, so implementing RPC client/server is an easy task.
Creating a server
First we need to define our server: it’s a set of methods it can perform and which will be exposed for our client. Which methods should be exposed? Those could be anything you want but we’ll start with implementing basic movements in all the directions and setting a desired speed.
1 | class GoPiGoController(object): |
Next we create and instance for our server which will listen for incoming requests
1 | from xmlrpc.server import SimpleXMLRPCServer |
Now we need to specify which exact methods should be triggered on incoming requests. We are able to register all the methods for our class with at once using register_instance
.
1 | server.register_introspection_functions() |
Finally, we launch our server and wait for some client to reach us.
1 | import sys |
Creating a client
Implementing a client is much simpler though we’ll add some complexity because of using Tkinter (make sure your Python support it following the instructions INVALID POST SLUG PROVIDED ).
1 | import xmlrpc.client |
While it does nothing we can implement a primitive gui for our client
1 | import os |
It consists of a master window, scale slider (for setting speed), quit button, two boolean flags (responsible for lights being turned on/off and flashing in random order) and s
field which holds a connection to our server. We then bind keyboard buttons to control ours robot movements with bind_controls
method.
1 | def bind_controls(self): |
And there is a callback for setting a speed (it got triggered when you change a value on a slider)
1 | def set_speed(self, value): |
The only thing left is to implement logic behind states of our LEDs.
1 | def flash(self, event): |
Basically we use our boolean flags to represent current state for lights which behaves like semaphore in order to comply to an action only if possible.
Now we can launch main loop of our application which will listen to any key events and in case of a match will invoke corresponding method on the client.
1 | root = tk.Tk() |
Note that we added a cleanup stage within finally
block which will close a connection and reset autorepeat to default value. After launching you should see a window similar to this one
Implementing controller methods
Now we are ready for the best part: making our robot actually move. In order to do that we need to use easygopigo3
library which has an API with all the available controls.
1 | from concurrent.futures import ThreadPoolExecutor |
All the underlying control methods are only a light proxies to gpg
object itself.
1 | def forward(self): |
There is one tricky part though which requires imported above futures module. In order to make our lights blink we need continuously turn them on and off. This will block the rest of the code, so we need a dedicated thread which will do that in the background. Let’s see how it works
1 | import time |
First we define all the available methods for turning a particular led on and their counterparts. After that we create a list of flags storing information about which led is active at the moment. Then within given interval we randomly toggle a state of one of them which creates a blinking effect.
Turning all the lights on is much simpler (the client code is responsible for not turning the lights on when flashing is in progress, no additional measurements was done on this side)
1 | def turn_lights_on(self): |
But how does our background thread know when to start flashing? We use our self.flashing
flag for that. It just periodically checks whether a flag is enabled and it can be enabled via exposed methods start_flash
and stop_flash
.
1 | def start_flash(self): |
I guees that’s it. Now launch python3 server.py
on your RaspberryPi and client on your laptop (python3 client.py
) and you are ready to navigate your robot around the world.
Nice work!
To see how it works altogether click Play on the video below.