EDUCATIONAL ROBOTICS

Introduction

Python is an interpreted, cross-platform, object-oriented programming language created by Guido van Rossum in 1991. It supports modules and packages, which encourages program modularity and code reuse and its simple, easy to learn syntax emphasises readability.

The Edbot Play&Code Python API is implemented as a Python 3 package. It allows a Python program to control your Edbot Play&Code robots. This guide assumes you are familiar with writing Python code.

Setting up

Install Python

Classic

Visit the Python downloads page to download and install Python 3.x for your platform. For Windows, make sure you select the option to add Python to the path.

Next you'll need the edbot Python package published through PyPI. You can install it with easy_install or pip. Using pip on the command line:

pip install edbot

Check the installed and latest version with:

pip index versions edbot

If you've already installed it, run the following command to make sure you have the latest version:

pip install --upgrade edbot

Bundled IDE

Alternatively you can install an integrated development environment (IDE) with a bundled Python interpreter, such as the popular Thonny.

Edbot Software

Make sure you are running the latest version of the Edbot Software available from the download page. For the purposes of this guide we'll assume you've set up your Edbot server and you're running it locally. If the Edbot Software is running remotely, you'll need to change the localhost references to the name of the remote server.

Folder structure

The Python examples folder is part of the Edbot Software installation. In Windows the folder is located in your 'Documents' folder:

Documents\Edbot\python

The folder should contain sample Python programs for each of the 6 different models you can make, including:

play_car.py
play_scorpion.py
play_puppy.py
play_windmill.py
play_bear.py
play_bird.py

Time to code

We're using classic Python 3.11.1 on Windows for this guide. Start a command prompt and run Python in interactive mode. If you're using Thonny, start it up and type the commands in the shell window.

> python
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec  6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "licence" for more information.
>>>

Connecting

The Edbot Play&Code Python API enables your Python program to connect to the Edbot Software which acts as the server. First things first. Import the edbot package.

>>> import edbot

Now create an instance of the EdbotClient class. Specify the Edbot server running locally on the default port of 8080. You can use the API to connect to a remote Edbot server too, but we'll stick to a server running locally for this guide. The client parameter can be any string to identify your program to the server. It defaults to "Python".

>>> ec = edbot.EdbotClient("localhost", 8080)

Your program should only create one instance of the EdbotClient class.

Next connect to the Edbot server both to send commands and receive data updates.

>>> ec.connect()

You can now query the robot names available. Let's assume we have configured an Edbot Play&Code called "Anna":

>>> ec.get_robot_names()
['Anna']

You can specify an optional model to only return robots of that type:

>>> ec.get_robot_names("play")
['Anna']

Waiting for control

After connecting to the Edbot server, your program will need to wait for control of the Edbot Play&Code.

>>> ec.wait_until_active("Anna")

Grant control using the active user menu in the Edbot Software. See below.

edbotsw python

If you're developing solo, the Edbot Software provides a convenient per-robot option "Open access" in the Server → Setup → Configure window. This will allow any connection to control the robot. Check this option while developing so that you don't need to give control each time you test your program. To stop other network users inadvertently accessing the robot, uncheck the "Available on network" option.

Commands

You can now send commands to your Edbot Play&Code. For example to play buzzer melody 0, use:

>>> ec.set_buzzer("Anna", "0/255")

To turn on motor 1 at full speed, use:

>>> ec.set_servo_speed("Anna", "1/100")

and to turn it off:

>>> ec.set_servo_speed("Anna", "1/0")

You can control the motors and built-in buzzer, access the Infrared (IR) and sound detection sensors and even get your Edbot Play&Code to speak using the API functions detailed in the Reference section.

Queries

After connecting, the Edbot Software sends real time data to your client program. Use the following function to get the data as a Python dictionary.

>>> ec.get_data()

The dictionary gives access to lots of useful information you can use in your code. Here's what the values mean:

{
  "server": {                      # server information
      "version": "6.0.0.1661",
      "platform": "Windows 10, 10.0.17134.523, amd64"
  },
  "auth": "9TBvXvf9",              # private session token
  "initComplete": True,            # true after connect() returns
  "robots": {
    "Anna": {                      # name of the robot
      "enabled": True,             # enabled?
      "connected": True,           # Bluetooth connected?
      "reporters": {               (1)
        ...
      },
      "activeUser": "Python...",   # currently active user
      "model": {                   # the robot model
          "name": "Edbot Play&Code",
          "type": "ERP50",
          "key": "play"
      }
    }
  },
  "user": "Python <Clive@[192.168.1.24]:51144>",
  "users": [
    "Python <Clive@[192.168.1.24]:51144>",
    "Scratch 2.0 <Clive@[192.168.1.24]:0>",
  ]
}
1 The reporters dictionary or None if not connected.

Reporters

The reporters dictionary provides real time data from the robot microcontroller.

The Edbot Play&Code has 4 built-in sensors (3 IR sensors and a clap counter), an internal buzzer and 2 motors. You can obtain the raw values of the built-in sensors from the following reporter keys:

"reporters": {
  "leftIR": 223,
  "centreIR": 14,
  "rightIR": 322,
  "clapCountLast": 0,
  "clapCountLive": 0,
  ...
}
Internal sensors

The built-in microphone detects the number of claps (loud noises) that have occurred in the last few seconds. This is called the live count (clapCountLive). When silence is detected, the live count is transferred to the last count (clapCountLast) and the live count is set back to 0.

There are 3 internal IR sensors: left, right and centre. To convert a raw sensor value to centimetres use the raw_to_CM50_dist function.

Current word

The speechCurrentWord reporter gives the current word as it is being spoken. The reporter is set to None when not speaking. It can be used to add visual emphasis during speech.

"reporters": {
  "speechCurrentWord": "Hello",
  ...
}

The current word reporter is only available on Windows and Mac platforms.

Asynchronous coding

The Python API enables you to supply a boolean wait parameter in calls to say. The default value of True causes the function to wait until the speech has completed before returning. This is convenient for command line programs but not so useful if you're writing a GUI program which will need to perform other tasks before the speech has completed.

To address this issue you can set the wait parameter to False and pass a unique sequence number in your call to say. A reporter will be set to this sequence number when the speech has completed. The following example illustrates the reporter data format. Here <auth> is the session token and <seq> is the sequence number passed in to the call.

"reporters": {
  "speechComplete": <auth>_self_s_<seq>,
  ...
}

The example code below demonstrates how to use this technique to detect when the speech has completed.

import time
import threading
import edbot

seq = 1
name = "Anna"
event = threading.Event()
ec = edbot.EdbotClient("localhost", 8080)

#
# This function will get called when the server sends a notification.
#
def my_callback(msg):
  try:
    complete = msg["robots"][name]["reporters"]["speechComplete"]
    if complete.endswith(str(seq)):
      # We've received our sequence number. We've finished speaking!
      event.set()
  except:
    pass

#
# Pass the callback in the call to connect().
#
ec.connect(my_callback)

#
# Wait for control.
#
print("Type Ctrl-C to exit")
print("Waiting to control " + name + "... ", end="", flush=True)
ec.wait_until_active(name)
print("Got control!")

#
# Say "Hello", wait until finished, then repeat.
#
while True:
  #
  # Reset the internal flag so that calls to event.is_set() will block until
  # event.set() is called in the callback.
  #
  event.clear()

  #
  # Now say "Hello", passing in the sequence number and return immediately.
  #
  print("Saying Hello!")
  ec.say(name, "Hello", wait=False, speech_seq=seq)

  # Don't use event.wait() - it isn't interruptible!
  while not event.is_set():
    time.sleep(0.1)

  # Increment the sequence number.
  seq += 1

Reference

EdbotClient

The EdbotClient class in the edbot package encapsulates the Edbot Play&Code Python API.

Constructor

Create a new instance by calling the constructor and assigning it to a variable.

edbot.EdbotClient(server, port, client=Python)

Parameters:

server

string

The ip address or hostname of the Edbot server.

port

integer

The port number on which the server is running.

client

string

Client description.

Returns:

A new EdbotClient instance.


connect

Open a connection to the Edbot server.

connect(callback=None)

Parameters:

callback

function

Optional callback function, see below.

If you supply a callback function it will be called when the server sends a change notification. Your function should be of the following form, where msg is of type dict.

my_callback(msg)

get_connected

Check if this client instance is connected to the Edbot server.

get_connected()

Returns:

True if connected, otherwise False.


disconnect

Close the connection to the Edbot server. This functon will initiate an orderly disconnection.

disconnect()

get_robot_names

Get an unsorted array containing the names of the robots configured on this server.

get_robot_names(model=None)

Parameters:

model

string

Optionally pass in the model key to filter a specific type of robot. Currently defined keys are "edbot", "dream" and "play".

Returns:

The robot names as an array of strings.


get_robot

Return the named robot as a dictionary.

get_robot(name)

Parameters:

name

string

The name of the robot.

Returns:

A dictionary with the following keys:

model

dict

A dictionary containing the robot model name, type and key.

enabled

boolean

True if the robot is enabled.

connected

boolean

True if the robot is connected via Bluetooth.

activeUser

string

The currently active user. None means open access.

reporters

dict

A dictionary containing the reporters or None if not connected via Bluetooth.


get_data

Get a dictionary containing the Edbot server data.

get_data()

Returns:

A dictionary with the following keys:

robots

dict

The robots configured on the server. Each robot is keyed on name and its value is a robot dictionary.

initComplete

boolean

If True the connection has finished initialising.

server

dict

A dictionary containing the server version and platform.

auth

string

A unique token allocated by the server used to identify this session.

user

string

The current user connection.

users

array

An Array of users connected to the server.


is_active

Does this connection have control of the robot? See wait_for_control.

is_active(name)

Parameters:

name

string

The name of the robot.

Returns:

True if the current user is active, otherwise False.

You can retrieve the name of the currently active user using:

get_robot(name)["activeUser"]

wait_until_active

Wait for control of the Edbot Play&Code. See wait_for_control.

wait_until_active(name)

Parameters:

name

string

The name of the robot.


set_servo_speed

Set the servo speed. This will immediately set the motor to the speed you specify.

set_servo_speed(name, path)

Parameters:

name

string

The name of the robot.

path

string

A string formed by the motor number followed by "/" followed by the speed as a percentage. Specify a negative percentage to rotate clockwise and a positive percentage to rotate anti-clockwise. Specify multiple motors by repeating the sequence, for example "1/50/2/50". To stop a motor just set its speed to zero.

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_buzzer

Play a note or built-in melody on the internal buzzer.

set_buzzer(name, path)

Parameters:

name

string

The name of the robot.

path

string

To play a note, path should be a string formed by the pitch followed by "/" followed by the duration. The pitch is a number from 0 to 48 and the duration is from 3 to 50 in units of 0.1 seconds. To play a built-in melody, specify path as a melody index followed by "/" followed by 255. Melody indices range from 0 to 24. We use the term melody loosely here!

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_custom

This advanced function allows you to set a value in the microcontroller's control table.

set_custom(name, path)

A description of the control table can be found at the following link:

As an example you can use this function to reset the clap counter using a path of "86/1/0".

Parameters:

name

string

The name of the robot.

path

string

A string formed by the control table address (0 - 65535) followed by a "/" followed by the size in bytes (1 or 2) followed by "/" followed by the option value to write (0 - 255 if 1 byte : 0 - 65535 if 2 bytes).

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_options

Set global options. These options are set to defaults when the robot is reset either by an explicit call to reset, or when the active user is changed on the Edbot server. Edbot Play&Code currently does not support any options.

set_options(name, path)

Parameters:

name

string

The name of the robot.

path

string

A string formed by the option name followed by "/" followed by the option value. Specify multiple options by repeating the sequence.

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


say

Specify text for the robot to speak. This function assumes the robot has been configured with speech on the Edbot server.

Unicode escapes are fully supported.

say(name, text, wait=True, speech_seq=None)

Parameters:

name

string

The name of the robot.

text

string

The text to speak.

wait

boolean

Wait for the speech to complete before returning.

speech_seq

integer

Supply a unique number for this speech request. See Asynchronous coding.

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


reset

Reset the Edbot Play&Code. This will stop the motors, set the last clap count back to 0 and halt any speech on a word boundary and empty the request queue.

reset(name)

Parameters:

name

string

The name of the robot.

Returns:

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


raw_to_CM50_dist

Convert the raw value from one of the three internal IR sensors to centimetres. The measuring range is 3cm to 20cm.

edbot.raw_to_CM50_dist(raw)

Parameters:

raw

integer

The raw sensor reading in the range 0 - 1023.

Returns:

Distance in centimetres rounded to 1 decimal place.

The function returns 100.0 if the raw value is 0 (out of range).

The sensor was calibrated using the distance between the front edge of the feet and a vertical white A4 card. The card was held a known distance from the sensor and the raw sensor value was noted. This was repeated for different distances. A non-linear power curve was then used to fit the data points. Note the sensor readings will differ for different coloured objects placed the same distance away.