Edbot

Support Template

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 Python API is implemented as a Python package. It allows a Python program to control your Edbots. This guide assumes you are familiar with writing Python code.

The Edbot Python API supports Python 3.

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

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. Follow the instructions in this article to add the edbot package to Thonny.

Edbot Software

Make sure you have installed the latest version of the Edbot Software 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.

The Edbot Software will only run in server mode if you’ve configured at least one Edbot.

Folder structure

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

Documents\Edbot\python

Similarly for Mac OS X and Linux:

Documents/Edbot/python

The folder should contain sample Python programs, including the following files:

edbot_arms.py
edbot_motions.py
edbot_motions_gui.py
edbot_twitter.py
  • edbot_arms.py selects the first Edbot and moves the Edbot arms up and back again.

  • edbot_motions.py selects the first Edbot, prompts for a motion number and runs the motion.

  • edbot_motions_gui.py displays a GUI window enabling you to select and run a motion.

  • edbot_twitter.py sends motions to an Edbot from formatted tweets to a monitored Twitter account.

Time to code

We’re using classic Python 3.5.2 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.5.2 [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "licence" for more information.
>>>

Connecting

The Edbot 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

It's a good idea to check the edbot package version corresponds with your version of the Edbot Software. Get the package version with the following command:

>>> print(edbot.__version__)
4.1.979

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, client="MyPythonApp")

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 Edbot names available. Let's assume we have configured an Edbot called "Bob":

>>> ec.get_edbot_names()
['Bob']

You can set a default Edbot name. This isn't necessary - you can pass the Edbot name as an optional parameter to most API functions - but it's convenient.

>>> ec.set_edbot_name("Bob")
True

Waiting for control

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

>>> ec.wait_until_active()

Grant control using the Edbot Software. See below.

edbotsw

The Edbot Software provides a convenient option "Bypass Active User" in the Main → Server Setup → Settings tab. Set this option while developing so that you don’t need to give control each time you test your program.

Commands

You can now send commands to your Edbot. For example to run a "bow 1" motion which has an id of 5, use:

ec.run_motion(5)

To move servo 1 to 200 degrees, use:

ec.set_servo_position("1/200")

You can run built-in motions, control the speed and position of individual servos, access servo data and external sensors and even get your Edbot to speak using the API methods 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:

{
  "edbots": {
    "Bob": {                     # name of the Edbot
      "type": "ERM161",          # the Edbot model
      "enabled": True,           # enabled?
      "connected": True,         # Bluetooth connected?
      "activeUser": "Python...", # currently active user
      "reporters": {             (1)
          ...
      },
      "colours": {               # servo LED colours & their indices
        "red": 1,
        "green": 2,
        ...
      },
      "motions": {               # the motion groups - first is "All"
        "All": [                 # array of motion names & their indices
          {
            "id": 5,
            "name": "bow 1"
          },
          ...
        ],
        ...
      }
    },
    ...
  },
  "auth": "...",                 # private session token
  "bypass": True,                # bypass active user?
  "user": "Python...",           # session user (me!)
  "users": [                     # array of connected users
    "Scratch...",
    "Python..."
  ]
}
1 The reporters dictionary or None if not connected.

Reporters

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

The Edbot has 4 sensor ports and the supplied IRSS-10 distance sensor mounted on the head is plugged into port1. You can obtain the raw value for a particular port from the following reporter keys:

"reporters": {
  "port1": 10,
  "port2": 350,
  "port3": 580,
  "port4": 22,
  ...
}

Use the raw_to_IRSS10_dist function to convert the raw value of the IRSS-10 to a distance in centimetres.

The sensor data may have been disabled with a call to set_options, for example during motion capture. In this mode, the values returned will be None.

Each servo has a key name beginning with servo- followed by a zero-padded 2 digit servo id. In default mode the servo data consists of the following keys:

  • The current position key in degrees to 1 decimal place.

  • The aligning key is True if the servo is in the process of moving after a call to set_servo_position.

  • The torque key is set to True if the servo is on.

  • The load key as a percentage to 1 decimal place.

  • The extended key is set to None.

For example:

"reporters": {
  "servo-01": {
    "position": 150.0,
    "aligning": False,
    "torque": False,
    "load": 0.0,
    "extended": None
  },
  "servo-02": {
    "position": 150.0,
    "aligning": False,
    "torque": False,
    "load": 0.0,
    "extended": None
  },
  ...
}

In extended servo mode, extra information is returned in the extended key:

  • The speed key as a percentage to 1 decimal place. For both keys, a positive value means CCW rotation and a negative value means CW rotation.

  • The voltage key is returned to 1 decimal place. This value can be used to detect low batteries.

  • The pid key reports the PID gain values as a colon separated list in the format P:I:D.

Here's an example:

"reporters": {
  "servo-01": {
    "position": 150.0,
    "aligning": False,
    "torque": False,
    "extended": {
      "speed": 10.0,
      "voltage": 7.4,
      "pid": "32:0:0"
    }
  },
  "servo-02": {
    "position": 150.0,
    "aligning": False,
    "torque": False,
    "extended": {
      "speed": 10.0,
      "voltage": 7.3,
      "pid": "32:0:0"
    }
  },
  ...
}

Sensor and servo data is NOT updated whilst a built-in motion is running.

The speech-current-word reporter gives the current word as it is being spoken. The reporter is set to null when not speaking. It can be used to add visual emphasis during speech, such as flashing the servo lights on and off.

"reporters": {
  "speech-current-word": "Hello",
  ...
}

Examples

Read through the following examples to gain an understanding of how to use the API. The reference section details the API methods with their parameters and return values.

Edbot arms

We'll begin by stepping through the Edbot arms example which selects the first Edbot and moves the arms up and back again.

import edbot (1)
import time

# Connect to the Edbot server.
ec = edbot.EdbotClient("localhost", 8080) (2)
ec.connect() (3)

# Choose the first Edbot we find and set this as a default.
found = False
edbots = ec.get_data()["edbots"]
for name, edbot in edbots.items():
  # Check the model type is actually an Edbot.
  if edbot["type"].startswith("ERM"):
    ec.set_edbot_name(name) (4)
    print("Found Edbot " + name)
    found = True
    break

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

  while True:
    entered = input("Type any key to move the arms (q to quit): ") (6)
    if entered == "q": break

    # Move those arms!
    ret = ec.set_servo_position("1/200/2/100") (7)
    if not ret["success"]:
      print(ret["message"])
      continue
    time.sleep(1.0)
    ret = ec.set_servo_position("1/150/2/150") (8)
    if not ret["success"]:
      print(ret["message"])
else:
  print("No Edbots available!")

ec.disconnect()
1 Import the "edbot" package.
2 Create a new EdboClient instance.
3 Connect to the Edbot server.
4 Set the first Edbot as default.
5 Wait for active control of the Edbot.
6 Wait for a key to be pressed.
7 Move servos 1 and 2.
8 Move them back.

Edbot motions

The next example selects the first Edbot, prompts for a motion number and runs the motion.

import edbot (1)

# Connect to the Edbot server.
ec = edbot.EdbotClient("localhost", 8080) (2)
ec.connect() (3)

# Choose the first Edbot we find and set this as a default.
found = False
edbots = ec.get_data()["edbots"]
for name, edbot in edbots.items():
  # Check the model type is actually an Edbot.
  if edbot["type"].startswith("ERM"):
    ec.set_edbot_name(name) (4)
    print("Found Edbot " + name)
    found = True
    break

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

  while True:
    entered = input('Enter a motion number (q to quit): ') (6)
    if entered == "q": break
    try:
      motion = int(entered)
    except ValueError:
      print("Not a valid motion number")
      continue

    # Run the motion.
    ret = ec.run_motion(motion) (7)
    if not ret["success"]:
          print(ret["message"])
else:
  print("No Edbots available!")

ec.disconnect()
1 Import the "edbot" package.
2 Create a new EdboClient instance.
3 Connect to the Edbot server.
4 Set the first Edbot as default.
5 Wait for active control of the Edbot.
6 Grab a motion number from the user.
7 Run the motion.

Asynchronous coding

The Python API enables you to supply a boolean wait parameter in calls to run_motion and say. The default value of True causes the function to block until the motion or 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 motion or 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 run_motion or say. A reporter will be set to this sequence number when the motion or speech has completed.

"reporters": {
  "motion-complete": 10,
  "speech-complete": 201,
  ...
}

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 = "Bob"
event = threading.Event()
ec = edbot.EdbotClient("localhost", 8080)

#
# This function will get called when the server sends a notification.
#
def my_callback(msg):
  try:
    data = ec.get_data()
    complete = data["edbots"][name]["reporters"]["speech-complete"]
    if complete == 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)

#
# Set the Edbot name for convenience.
#
ec.set_edbot_name(name)

#
# Wait for control.
#
print("Type Ctrl-C to exit")
print("Waiting to control " + name + "... ", end="", flush=True)
ec.wait_until_active()
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("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 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 type on the Edbot server.

Return

A new EdbotClient instance.


get_server

Get the server name or ip address.

get_server()

Parameters

None.

Return

A string representing the server name or ip address.


get_port

Get the server port number.

get_port()

Parameters

None.

Return

The server port number.


connect

Open a connection to the Edbot server.

connect(callback=None)

Parameters

callback

function

Optional callback function, see below.

Return

None.

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)

The Edbot Software will only run in server mode if you've set up at least one Edbot.


disconnect

Close the connection to the Edbot server.

disconnect()

Parameters

None.

Return

None.


get_edbot_names

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

get_edbot_names()

Parameters

None.

Return

The Edbot names as an array of strings.


get_edbot

Return the named Edbot as a dictionary.

get_edbot(name=None)

Parameters

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys:

type

string

The Edbot model type.

enabled

boolean

True if the Edbot is enabled.

connected

boolean

True if the Edbot is connected via Bluetooth.

activeUser

string

The currently active user.

reporters

dict

A dictionary containing the reporters such as sensor values.

colours

dict

The available servo LED colours as a dictionary. Each entry has the colour name as a key and the colour index as a value.

motions

dict

The available Edbot motions. The motion group name is used as a key, with the corresponding value being an array of motions. Each motion in the array has an id key and a name key which represent the motion id and name.


get_data

Get a dictionary containing the Edbot server data.

get_data()

Parameters

None.

Return

A dictionary with the following keys:

edbots

dict

The Edbots configured on the server. See the Edbot dictionary above.

auth

string

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

bypass

boolean

Bypass the active user control?

user

string

The current user connection.

users

array

The users connected to the server.


is_active

Does this connection have control of the Edbot? See Waiting for control.

is_active(name=None)

Parameters

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

True if the current user is active, otherwise False.

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

get_edbot(name=None])["activeUser"]

wait_until_active

Wait for control of the Edbot. See Waiting for control.

wait_until_active(name=None)

Parameters

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

None.


set_edbot_name

Set the default Edbot name.

set_edbot_name(name)

Parameters

name

string

The name of the Edbot.

Return

True on success, otherwise False.


run_motion

Run the motion referenced by the passed in motion id.

run_motion(motion_id, wait=True, motion_seq=None, name=None)

Parameters

motion_id

integer

The motion number.

wait

boolean

Wait for the motion to complete before returning.

motion_seq

integer

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

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.

Before the motion is run:

  • Servo LEDs are switched off - if the motion_leds option is set to the default on.

  • Servo speeds are reset to 100%.

When the motion completes:

  • Servo LEDs are switched off - if the motion_leds option is set to the default on.

  • Servo PID controller values are reset to {32, 0, 0}.

  • Servos remain switched on.

You can get the motion dictionary, which maps motion ids to names, using:

get_edbot(name=None])["motions"]["All"]

set_servo_torque

Switch servos on or off.

set_servo_torque(path, name=None)

Parameters

path

string

A string formed by the servo number followed by "/" followed by 0 or 1 to turn the servo off or on respectively. Specify multiple servos by repeating the sequence, for example "1/0/2/0/3/1/4/1". Servo number 0 means all servos, so "0/0" will turn all servos off.

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_servo_led

Set the colours of the servo LEDs.

set_servo_led(path, name=None)

Parameters

path

string

A string formed by the servo number followed by "/" followed by the servo colour index. The colour table is returned in the Edbot dictionary. Specify multiple servos by repeating the sequence, for example "1/3/2/3/3/3/4/3". Servo number 0 means all servos, so "0/3" will set all servo LEDs to colour index 3.

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.

You can get the colour dictionary, which maps colour names to ids, using:

get_edbot(name=None])["colours"]

set_servo_speed

Set the servo speed.

set_servo_speed(path, name=None)

Parameters

path

string

A string formed by the servo number followed by "/" followed by the speed which should be a percentage greater than zero. Specify multiple servos by repeating the sequence, for example "1/50/2/50/3/50/4/50". Servo number 0 means all servos, so "0/12.5" will set all servos to one eighth speed.

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_servo_position

Set the servo position.

set_servo_position(path, name=None)

Parameters

path

string

A string formed by the servo number followed by "/" followed by the position which is an angle from 0 to 300 degrees. Specify multiple servos by repeating the sequence, for example "1/250/2/50". servo angle

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


set_servo_pid

Set the servo PID gain values.

set_servo_pid(path, name=None)

Parameters

path

string

A string formed by the servo number followed by "/", then three values each separated by "/" representing the required P gain, I gain and D gain values. Specify multiple servos by repeating the sequence, for example "1/32/0/0/2/32/0/0".

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.

Edbot uses state-of-the-art Robotis XL-320 servos. These advanced servos feature PID controllers. A PID controller continuously calculates an error value as the difference between the goal position and the current position. It applies a correction based on proportional (P), integral (I), and derivative (D) terms which gives this type of controller its name. The proportional term is the easiest to understand: The servo applies an electrical current proportional to the error. The integral term increases in relation to the time the error has been present, as well as the size. The derivate term applies to the rate of change of error. For more information on PID controllers consult Wikipedia.

All 3 values should be between 0 and 254, the default PID is {32, 0, 0}.


set_options

Set global options. These options are set to defaults when the Edbot is reset either by an explicit call to reset, or when the active user is changed on the Edbot server.

set_options(path, name=None)

Parameters

path

string

A string formed by the option name followed by "/" followed by the option value. Specify multiple options by repeating the sequence. Edbot currently supports the following options:

motion_leds

integer

Specify 1 to turn on the motion LEDs (default) or 0 to switch them off.

sensor_data

integer

Specify 1 to enable sensor data (default) or 0 to disable.

ext_servo_data

integer

Specify 1 to enable extended servo data or 0 for standard servo data (default).

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

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 Edbot to speak. This method assumes the Edbot has been configured with speech on the Edbot server. Unicode escapes are fully supported.

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

Parameters

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.

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


reset

Reset the Edbot. This will stop any current speech, stop any current motion, switch off the servo LEDs, set defaults and empty the request queue.

The servo speed settings are not reset due to limitatons in the firmware.

reset(name=None)

Parameters

name

string

The name of the Edbot. Can be omitted if set with set_edbot_name.

Return

A dictionary with the following keys.

success

boolean

True on success, otherwise False.

message

string

The Edbot server response message.


raw_to_IRSS10_dist

Convert the raw value from the IRSS-10 IR sensor to centimetres. The measuring range is 3cm to 30cm.

edbot.raw_to_IRSS10_dist(raw)

Parameters

raw

integer

The raw sensor reading in the range 0 - 1023.

Return

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.