Package: toio-py
toio.pyThis is a library for controllingtoio™Core Cubefrom Python.Based ontoio Core Cube Specificationsv2.3.0.（日本語版 README.md はこちら）FeaturesUsesbleakfor Bluetooth communicationSupports Python 3.11 and later versionsMulti-platform (Windows, Linux, macOS)No dedicated Bluetooth dongle requiredAsynchronous API (ToioCoreCube API) based on the toio Core Cube Specifications and synchronous API (SimpleCube API) for easy cube controlScanning function by specifying BLE addresses and cube-specific namesAPI to control cube functions classified by characteristics (ToioCoreCube API)Ability to scan paired cubes (Windows only)System requirementsPrimaly tested environmentWindows: Windows 10 (21H2)Secondary tested environmentLinux: Ubuntu22.04macOS: macOS 12(Monterey)Setup and tutorialSee below for instructions on how to set up and run the tutorial.Setup Guide (English)Setup Guide (Japanese)Setup Guide (Chinese)SimpleCube APISeeSIMPLE_API.en.mdfor information on the SimpleCube API for easily controlling toio Core Cubes.SIMPLE_API.en.md (English)SIMPLE_API.ja.md (Japanese)API documentAPI DocumentImplementation overviewtoio.py consists of two classes, Scanner and ToioCoreCube.ScannerClass for scanning cubes via the BLE interface.You can scan for cubes in the following ways:Scan for nearby cubesScan for a specific cube by name (the last 3 characters of the toio Core Cube name)The following is available only for Windows and Linux:Scan for a specific cube by BLE addressThe following is available only for Windows:Scan for cubes registered (paired) with OSToioCoreCubeClass for controlling the cube.ToioCoreCube has subclasses corresponding to the characteristics described intoio CoreCube Specifications. You access the various functions of the cube via these subclasses.Sample codeScan and connectUseBLEScanner.scan().The argument is the number of cubes to find in the scan.If the specified number of cubes are not found by the timeout (default value is 5 seconds), it returns a list of the number of cubes found at the time of the timeout.The following sample scans and connects nearby cubes.Disconnects 3 seconds after connecting.importasynciofromtoioimport*asyncdefscan_and_connect():dev_list=awaitBLEScanner.scan(num=1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()awaitasyncio.sleep(3)awaitcube.disconnect()return0if__name__=="__main__":asyncio.run(scan_and_connect())Scan and connect (scan by cube name)UseBLEScanner.scan_with_id().The argument isset (set type), a 3-digit string at the end of the cube.
The argument is given as set even if only one unit is to be scanned.If the specified number of cubes are not found by the timeout (default value is 5 seconds), it returns a list of cubes found at the time of the timeout.dev_list=awaitBLEScanner.scan_with_id(cube_id={"C7f"})Scan and connecttoio Core Cube-C7f.Disconnects 3 seconds after connecting.importasynciofromtoioimport*asyncdefscan_and_connect():dev_list=awaitBLEScanner.scan_with_id(cube_id={"C7f"})assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()awaitasyncio.sleep(3)awaitcube.disconnect()return0if__name__=="__main__":asyncio.run(scan_and_connect())Scan and connect (scan paired cubes: supported on Windows only)Windows only, paired cubes can be scanned.UseBLEScanner.scan_registered_cubes().The argument is the number of cubes to find in the scan.If the specified number of cubes are not found by the timeout (default value is 5 seconds), it returns a list of the number of cubes found at the time of the timeout.dev_list=awaitBLEScanner.scan_registered_cubes()Scan for paired cubes and connect them. (Pair the cube with Windows using "Add Bluetooth Device" before doing this.)Disconnects 3 seconds after connecting.importasynciofromtoioimport*asyncdefscan_and_connect():dev_list=awaitBLEScanner.scan_registered_cubes(num=1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()awaitasyncio.sleep(3)awaitcube.disconnect()return0if__name__=="__main__":asyncio.run(scan_and_connect())Get the cube locationUse the classToioCoreCube.api.id_informationto get the location information of the cube.
This class provides access to theread sensor characteristic.The following code reads and displays the cube ID information 200 times.
It usesread()to read to the characteristic.importasynciofromtoioimport*asyncdefread_id():device_list=awaitBLEScanner.scan(1)assertlen(device_list)cube=ToioCoreCube(device_list[0].interface)awaitcube.connect()forninrange(200):pos=awaitcube.api.id_information.read()print("%4d:%s"%(n,str(pos)))awaitcube.disconnect()if__name__=="__main__":asyncio.run(read_id())Get the cube location (using notification)You can receive notifications from the cube by registering a notification handler withregister_notification_handler().
Notifications are per each characteristic. A notification handler registered withToioCoreCube.api.id_information.register_notification_handler()receives
receive only notifications from the read sensor.The following code reads the ID by notification.After 10 seconds, the handler is unregistered and disconnected.importasynciofromtoioimport*# Notification handlerdefnotification_handler(payload:bytearray):id_info=IdInformation.is_my_data(payload)print(str(id_info))asyncdefread_id():# connect to a cubedev_list=awaitBLEScanner.scan(1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()# add notification handlerawaitcube.api.id_information.register_notification_handler(notification_handler)awaitasyncio.sleep(10)# remove notification handlerawaitcube.api.id_information.unregister_notification_handler(notification_handler)awaitcube.disconnect()return0if__name__=="__main__":asyncio.run(read_id())The complete code that keeps displaying ID information until Ctlr-C is pressed isexamples/read_position.py.Motor controlTheToioCoreCube.api.motorclass is used to control the motor.
This class provides access to themotor's characteristic.The following code usesmotor_control()to rotate the cube in place for 2 seconds.importasynciofromtoioimport*asyncdefmotor_1():# connect to a cubedev_list=awaitBLEScanner.scan(1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()# goawaitcube.api.motor.motor_control(10,-10)awaitasyncio.sleep(2)# stopawaitcube.api.motor.motor_control(0,0)awaitcube.disconnect()return0if__name__=="__main__":asyncio.run(motor_1())Motor control (move to specified position)Usemotor.motor_control_target()to move the cube to a specified position on the mat.importasynciofromtoioimport*# Notification handlerdefnotification_handler(payload:bytearray):id_info=IdInformation.is_my_data(payload)print(str(id_info))asyncdefmotor_2():# connect to a cubedev_list=awaitBLEScanner.scan(1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()awaitcube.api.motor.register_notification_handler(notification_handler)awaitcube.api.motor.motor_control_target(timeout=5,movement_type=MovementType.Linear,speed=Speed(max=100,speed_change_type=SpeedChangeType.AccelerationAndDeceleration),target=TargetPosition(cube_location=CubeLocation(point=Point(x=200,y=200),angle=0),rotation_option=RotationOption.AbsoluteOptimal,),)awaitasyncio.sleep(4)awaitcube.disconnect()if__name__=="__main__":asyncio.run(motor_2())Motor control (move to multiple specified positions)Usemotor.motor_control_multiple_targets()to move the cube to a specified position on multiple mats.importasynciofromtoioimport*asyncdefmotor_3():# connect to a cubedev_list=awaitBLEScanner.scan(1)assertlen(dev_list)cube=ToioCoreCube(dev_list[0].interface)awaitcube.connect()targets=[TargetPosition(cube_location=CubeLocation(point=Point(x=250,y=250),angle=0),rotation_option=RotationOption.AbsoluteOptimal),TargetPosition(cube_location=CubeLocation(point=Point(x=120,y=170),angle=0),rotation_option=RotationOption.AbsoluteOptimal),]awaitcube.api.motor.motor_control_multiple_targets(timeout=5,movement_type=MovementType.Linear,speed=Speed(max=100,speed_change_type=SpeedChangeType.AccelerationAndDeceleration),mode=WriteMode.Overwrite,target_list=targets,)awaitasyncio.sleep(5)awaitcube.disconnect()if__name__=="__main__":asyncio.run(motor_3())