Linux on Thymio with Raspberry PI and Python

The following example shows how to control Thymio II from software that is running on the Raspberry PI. The software will acquire the values of the proximity sensors of the Thymio II, process these values so that Thymio II will follow an object that is moving in front of it.

For this example, we have equipped a Thymio II with a Raspberry PI, a portable USB battery (Golf power bank 5200mAh) and a Wi-fi Edimax ew-7811un. Here are some pictures showing the robot:

Side view
2014-01-31%2013.46.45.jpg

Rear view

2014-01-31%2013.47.04.jpg

Front view

2014-01-31%2013.47.15.jpg

The Thymio can be controlled directly from software running on the Raspberry PI. For this purpose, we use asebamedulla instead of asebaswitch, in order to use the DBus library, integrated in asebamedulla, for the communication between the software and the Thymio II.

In order to run asebamedulla on your Raspberry PI, it is almost the same operation as for asebaswitch

asebamedulla "ser:device=/dev/ttyACM0"

supposing again that your Thymio II is the device /dev/ttyACM0.

Now that your Raspberry PI is connected to your Thymio, you can write a small software that can send and receive commands using the DBus library. We chose Python language to write the software, but it can also be written in C, C++..

The program that we are going to present to you interfaces with Aseba using D-Bus. It also uses the GObject and OptionParser libraries. You need to install the GObject library on your Raspberry PI with the command:

sudo apt-get install python-gobject

If you are a beginner with Python, a good tutorial for learning the Python language can be found here
http://docs.python.org/2/tutorial/

Here is the Python script that we are using:

import dbus
import dbus.mainloop.glib
import gobject
from optparse import OptionParser
 
proxSensorsVal=[0,0,0,0,0]
 
def Braitenberg():
    #get the values of the sensors
    network.GetVariable("thymio-II", "prox.horizontal",reply_handler=get_variables_reply,error_handler=get_variables_error)
 
    #print the proximity sensors value in the terminal
    print proxSensorsVal[0],proxSensorsVal[1],proxSensorsVal[2],proxSensorsVal[3],proxSensorsVal[4]
 
    #Parameters of the Braitenberg, to give weight to each wheels
    leftWheel=[-0.01,-0.005,-0.0001,0.006,0.015]
    rightWheel=[0.012,+0.007,-0.0002,-0.0055,-0.011]
 
    #Braitenberg algorithm
    totalLeft=0
    totalRight=0
    for i in range(5):
         totalLeft=totalLeft+(proxSensorsVal[i]*leftWheel[i])
         totalRight=totalRight+(proxSensorsVal[i]*rightWheel[i])
 
    #add a constant speed to each wheels so the robot moves always forward
    totalRight=totalRight+50
    totalLeft=totalLeft+50
 
    #print in terminal the values that is sent to each motor
    print "totalLeft"
    print totalLeft
    print "totalRight"
    print totalRight
 
    #send motor value to the robot
    network.SetVariable("thymio-II", "motor.left.target", [totalLeft])
    network.SetVariable("thymio-II", "motor.right.target", [totalRight])    
 
    return True
 
def get_variables_reply(r):
    global proxSensorsVal
    proxSensorsVal=r
 
def get_variables_error(e):
    print 'error:'
    print str(e)
    loop.quit()
 
if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option("-s", "--system", action="store_true", dest="system", default=False,help="use the system bus instead of the session bus")
 
    (options, args) = parser.parse_args()
 
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
    if options.system:
        bus = dbus.SystemBus()
    else:
        bus = dbus.SessionBus()
 
    #Create Aseba network 
    network = dbus.Interface(bus.get_object('ch.epfl.mobots.Aseba', '/'), dbus_interface='ch.epfl.mobots.AsebaNetwork')
 
    #print in the terminal the name of each Aseba NOde
    print network.GetNodesList()
 
    #GObject loop
    print 'starting loop'
    loop = gobject.MainLoop()
    #call the callback of Braitenberg algorithm
    handle = gobject.timeout_add (100, Braitenberg) #every 0.1 sec
    loop.run()

The algorithm implemented will make Thymio II follow an object that is moving in front of it, using its proximity sensors and the Braitenberg Vehicle principle. The Braitenberg vehicle consists of linking the proximity sensors with the motor inside the software, and depending on the values produced by the five front proximity sensors of Thymio II, the robot will orient itself toward the object that is moving.

In this program, we use the command network.SetVariable and network.GetVariable to set and read the values of Aseba variables. For instance, to make the left wheel of the robot move forward with a speed of 100, we use the command network.SetVariable to set the variable "motor.left.target" of the Aseba Node "thymio-II" to the value [100]

network.SetVariable("thymio-II", "motor.left.target", [100])

If we want to read variables, for example the proximity sensors, we should use network.GetVariable with the Aseba Node name "thymio-II" and the name of the variable "prox.horizontal" which is the name of the variable that contains a list of the values of all the 7 proximity sensors of the Thymio II.

network.GetVariable("thymio-II", "prox.horizontal",reply_handler=get_variables_reply,error_handler=get_variables_error)

In order to know the name of the Aseba node of your Thymio II, the instruction

network = dbus.Interface(bus.get_object('ch.epfl.mobots.Aseba', '/'), dbus_interface='ch.epfl.mobots.AsebaNetwork')
print network.GetNodesList()

will print the list of the Aseba Nodes. In order to know the name of the node, for instance in our case the name of the node was "thymio-II", you should just execute the code once and read in the terminal the name of the node, and then go back to the code and replace the node's name for the instructions that send and receive variables.

If you want to send an event to the Thymio II from the Raspberry PI, you can call network.SendEvent. For example the following instruction will send Event 1 with 2 arguments, with values of respectively 5 and 7.

network.SendEvent(1, [5,7])
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License