├── .gitignore ├── BotConnect ├── __init__.py └── botConnect.py ├── README.md └── botTest.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class -------------------------------------------------------------------------------- /BotConnect/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelbink/raspberry-pi-ozobot-evo/5de09556efa06565c7941bcec285840e76a391a1/BotConnect/__init__.py -------------------------------------------------------------------------------- /BotConnect/botConnect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | if sys.version_info[0] < 3: 5 | print("This script requires Python version 3.X or higher") 6 | sys.exit(1) 7 | 8 | from bluepy import btle 9 | 10 | class Robot(object): 11 | 12 | mac_addr = '' 13 | name = '' 14 | 15 | def __init__(self, mac_addr, name): 16 | self.mac_addr = mac_addr 17 | self.name = name 18 | 19 | class RobotFinder(object): 20 | 21 | def __init__(self): 22 | self.robots = [] 23 | 24 | def findRobots(self): 25 | scanner = btle.Scanner().withDelegate(btle.DefaultDelegate()) 26 | devices = scanner.scan(10.0) 27 | 28 | for dev in devices: 29 | for (adtype, desc, value) in dev.getScanData(): 30 | if(adtype == 9 and value.startswith('OzoEvo')): 31 | print(adtype, dev.addr, value) 32 | self.robots.append(Robot(dev.addr, value)) 33 | 34 | class RobotControl(object): 35 | TRANSMIT_UUID_DRIVE = "8903136c-5f13-4548-a885-c58779136702" 36 | TRANSMIT_UUID_CONTROL = "8903136c-5f13-4548-a885-c58779136703" 37 | 38 | def __init__(self, addr): 39 | self._mac = addr 40 | 41 | def connect(self): 42 | self._p = btle.Peripheral(self._mac, btle.ADDR_TYPE_RANDOM) 43 | self._p_transmit_drive = self._p.getCharacteristics(uuid=self.TRANSMIT_UUID_DRIVE)[0] 44 | self._p_transmit_control = self._p.getCharacteristics(uuid=self.TRANSMIT_UUID_CONTROL)[0] 45 | self.d = self._p_transmit_drive 46 | self.c = self._p_transmit_control 47 | 48 | # send stop file command to OzoBot to enable for sending commands 49 | self.c.write(b"\x50\x02\x01") 50 | 51 | def disconnect(self): 52 | pass 53 | 54 | def drive(self, leftWheel, rightWheel, duration): 55 | byteArray = [] 56 | byteArray.append(64) 57 | byteArray.append(leftWheel & 255) 58 | byteArray.append(leftWheel >> 8 & 255) 59 | byteArray.append(rightWheel & 255) 60 | byteArray.append(rightWheel >> 8 & 255) 61 | byteArray.append(duration & 255) 62 | byteArray.append(duration >> 8 & 255) 63 | command = bytes(byteArray) 64 | return(command) 65 | 66 | def led(self, led, red, green, blue): 67 | byteArray = [] 68 | byteArray.append(68) 69 | byteArray.append(led & 255) 70 | byteArray.append(led >> 8 & 255) 71 | byteArray.append(red) 72 | byteArray.append(green) 73 | byteArray.append(blue) 74 | command = bytes(byteArray) 75 | return(command) 76 | 77 | 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # raspberry-pi-ozobot-evo 2 | Control your [Ozobot Evo](https://amzn.to/2D91W3s)* with your Raspberry Pi via Bluetooth 3 | 4 | Ozobot Evo is a toy robot that has multiple features like automatic path following, remote control via App, proximity sensors, and LEDs. 5 | In this repo you find the code to control the [Ozobot Evo](https://amzn.to/2D91W3s)* with a Raspberry Pi. 6 | 7 | 8 | ## Special characteristics of the Ozobot Evo protocol 9 | ### MAC address 10 | The Ozobot Evo uses different MAC-addresses at each start. In order to connect to the right Bluetooth devivce, you ahve to identify it by name. The names of the Ozobot Evo devices always start with "OzoEvo" followed by an integer 11 | 12 | ### The StopFile command 13 | In order to be able to send commands to the OzoBot after having connected to it, you have to send an initial stop file command. Only if you do that, the Ozobot will react to the commands that are sent to it. The stop file commnd consists of thre bytes with the hex values 50, 02, 01 14 | ``` 15 | bot1.c.write(b"\x50\x02\x01") 16 | ``` 17 | ### Bluetooth characteristics 18 | The Ozobot offers two different characteristics. One is only for drive commands, the other for all other types of commands. 19 | ``` 20 | TRANSMIT_UUID_DRIVE = "8903136c-5f13-4548-a885-c58779136702" 21 | TRANSMIT_UUID_CONTROL = "8903136c-5f13-4548-a885-c58779136703" 22 | ``` 23 | 24 | ### Command byte arrays 25 | The format of the byte arrays differs in length based on the command. It always starts with an identifier of the command itself (e.g. 64 for drive and 68 for led), followed by the actual payload. 26 | 27 | In many cases, some of the parameters are added twice to the paylod, whereas one of the values is shifted by 8 bits. 28 | 29 | 30 | * Affiliate Links 31 | -------------------------------------------------------------------------------- /botTest.py: -------------------------------------------------------------------------------- 1 | from BotConnect import botConnect 2 | 3 | robotFinder = botConnect.RobotFinder() 4 | robotFinder.findRobots() 5 | 6 | bot1 = botConnect.RobotControl(robotFinder.robots[0].mac_addr) 7 | bot1.connect() 8 | 9 | bot1.c.write(b"\x50\x02\x01") 10 | 11 | bot1.d.write(bot1.drive(500,500,1000)) 12 | 13 | bot1.c.write(bot1.led(255,100,100,20)) 14 | --------------------------------------------------------------------------------