The Thymio Robot
The robot, a Thymio II, is a robot designed for educational purposes. All components (hardware and software) are open source. The robot consists of more than 20 sensors, many LEDs, two motors, a microphone and a loudspeaker. To make the already very powerful tool even more superior we connected a Raspberry Pi to it, allowing us to not only take full control over every aspect of the robot, but also using Python as a programming language for the device.
Fig. 1: Our Thymio robot in action. On its top resides a Raspberry Pi, which is powered by an external power bank.
The code
The program controlling our robot is relatively simple in principle. It can not only be addressed from the perspective of the robot, but also be considered in its entirety with the reactions of the bioreactor.
First, the robot connects to a network to link to the bioreactor. After that, it initializes its sensors and switches into the main loop.
Here the robot iterates some commands:
The robot queries the sensor values of the distance sensors and, depending on a predetermined threshold, rules if there is an object in front of it or not.
If an object has been detected, this information is sent to the reactor (which then pumps a certain amount of bacterial culture into the reaction chamber, where the bacteria are either heated or the pH of their medium is changed).
If no object is detected, this information is also transmitted to the reactor (which then pumps a certain amount of bacterial culture into the reaction chamber, but in this case does not heat or change the pH of the medium).
Thereafter, the robot must wait for a response from the reactor. The reactor pumps the bacterial culture into the measuring chamber and checks whether fluorescent proteins can be detected.
In that case, this information is transmitted to the robot and depending on whether fluorescent proteins were detected (results in a rotation) or not (resulting in a movement forward), the robot reacts. After this reaction a new iteration of the main loop starts.
This is our code controlling the Thymio:
This is our code controlling the Thymio:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | #!/usr/bin/python2 import dbus import dbus.mainloop.glib import gobject import sys import socket import time import logging #from w1thermsensor import W1ThermSensor from optparse import OptionParser # proximity sensor readaout values proxSensorsVal = [0, 0, 0, 0, 0] # server ip and port host = '192.168.43.150' port = 4343 logger = logging.getLogger('colibot') debug = False counter = 0 SENSOR_THRESHOLD = 3300 DRIVE_DIST = 400 TURN_DIST = 180 def dbus_reply(): pass def dbus_error(e): # logger.info 'error %s' # logger.info str(e) pass def control(): # get the values of the sensors network.GetVariable("thymio-II", "prox.horizontal", reply_handler=get_variables_reply, error_handler=get_variables_error) # send proximity sensor reading to colis reply = coli_com() if reply == 0: for i in range(0, DRIVE_DIST): network.SetVariable("thymio-II", "motor.left.target", [100]) network.SetVariable("thymio-II", "motor.right.target", [100]) if reply == 1: for i in range(0, TURN_DIST): network.SetVariable("thymio-II", "motor.left.target", [100]) network.SetVariable("thymio-II", "motor.right.target", [-100]) network.SetVariable("thymio-II", "motor.left.target", [0]) network.SetVariable("thymio-II", "motor.right.target", [0]) return True def get_variables_reply(r): global proxSensorsVal proxSensorsVal = r def get_variables_error(e): logger.info('error: ') logger.info(str(e)) loop.quit() def coli_com(): global debug sum_prox = proxSensorsVal[0] + proxSensorsVal[1] + proxSensorsVal[2] + proxSensorsVal[3] + proxSensorsVal[4] sides = proxSensorsVal[0] + proxSensorsVal[4] global counter counter += 1 if (counter % 2): # print("dirrrrty hack to take every second measurement only") return 6 logger.info('# # # # # # # # # # # # # # # # #') logger.info(' cycle {}'.format(counter/2)) logger.info("Proximity sensor sum: " + str(sum_prox)) try: if (sum_prox > SENSOR_THRESHOLD): logger.info("Obstacle detected!") if not debug: # send data to server s.sendto(str.encode('obstacle'), (host, port)) logger.info("Sent 'obstacle' to reactor.") if debug == True: reply = 'turn' else: logger.info("No obstacle") if not debug: # send data to server s.sendto(str.encode('clear'), (host, port)) logger.info("Sent 'clear' to reactor.") if debug == True: reply = 'drive' if debug == False: # receive data d = s.recvfrom(1024) reply = d[0] addr = d[1] logger.info('Server reply : ' + str(reply)) # logger.info('Executing ...') logger.info(' #') logger.info('# # # # # # # # # # # # # # # # #') logger.info('') if (reply.decode("utf-8") == 'turn'): # s.sendto(str.encode('thanks'), (host, port)) return 1 if (reply.decode("utf-8") == 'drive'): # s.sendto(str.encode('thanks'), (host, port)) return 0 else: return 6 except socket.error as msg: logger.info('Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) def cam_sync_at_start(): network.SetVariable("thymio-II", "motor.left.target", [300]) network.SetVariable("thymio-II", "motor.right.target", [300]) time.sleep(1) network.SetVariable("thymio-II", "motor.left.target", [0]) network.SetVariable("thymio-II", "motor.right.target", [0]) network.SetVariable("thymio-II", "motor.left.target", [-300]) network.SetVariable("thymio-II", "motor.right.target", [-300]) time.sleep(1) network.SetVariable("thymio-II", "motor.left.target", [0]) network.SetVariable("thymio-II", "motor.right.target", [0]) if __name__ == '__main__': # format FORMAT = "[%(asctime)s ] %(message)s" fileHandler = logging.FileHandler('log.txt') fileHandler.setFormatter(logging.Formatter(FORMAT)) logger.addHandler(fileHandler) logging.basicConfig(level=20, format=FORMAT, datefmt='%d.%m.%Y %H:%M:%S') parser = OptionParser() parser.add_option("-s", "--system", action="store_true", dest="system", default=False, help="use the system bus instead of the session bus") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False) (options, args) = parser.parse_args() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) # use system bus instead of session bus if option is passed if options.system: bus = dbus.SystemBus() else: bus = dbus.SessionBus() if options.debug: debug = True # Create Aseba network network = dbus.Interface(bus.get_object( 'ch.epfl.mobots.Aseba', '/'), dbus_interface='ch.epfl.mobots.AsebaNetwork') # logger.info in the terminal the name of each Aseba NOde #logger.info(network.GetNodesList()) # to sync camera: logger.info("cam-sync:") cam_sync_at_start() logger.info("Start logging") logger.info("###############################") logger.info(" ColiBot Thymio controller ") logger.info("-------------------------------") logger.info("... starting: ...") # create dgram udp socket try: logger.info("Creating socket.") s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) except socket.error: logger.info('Failed to create socket') sys.exit() # GObject loop # logger.info 'starting loop' loop = gobject.MainLoop() # call the callback of control flow handle = gobject.timeout_add(1000, control) # every 0.1 sec loop.run() |