Welcome to WonderPy’s documentation!

This document provides instructions to control Wonder Workshop’s “Dash” and “Cue” robots with the Adafruit Clue board and CircuitPython.

Dash and Cue educational robots used in a wide variety of settings, including classrooms and homes. Read more at here.

The Adafruit Clue is a small microcontroller development board with built-in Bluetooth BLE capabilities. Read more about the Adafruit Clue here.

CircuitPython is a small implementation of the Python programming language that can run on small microcontrollers, such as the Adafruit Clue.

Tutorial

This tutorial assumes that you are using a standard Dash robot with an Adafruit Clue.

Set up your Adafruit Clue

To get started, we will need to set up your Adafruit Clue.

Install CircuitPython

First, you will need to install CircuitPython version 7.0.0. This tutorial will provide abridged setup instructions. Up-to-date instructions can be found here.

  1. Download the CircuitPython 7.0.0 image here.

  2. Attach your Adafruit Clue to a PC computer with a Micro-USB cable.

  3. Double-click the reset button on the back of the Adafruit Clue. It should now show up as a drive called “CLUEBOOT”.

  4. Copy the image file downloaded earlier (should be a .uf2 file) to the CLUEBOOT drive. The Clue board should reboot and CircuitPython should print a welcome message onto the screen. The clue board should now show up as a drive called “CIRCUITPY”.

Install CircuitPython/Adafruit libraries

Next, you will need to install CircuitPython libraries. Adafruit and CircuitPython provide libraries and modules to support a wide variety of sensors and peripherals. In order to control Wonder Workshop robots, a library must be installed in order to use the on-board Bluetooth BLE module.

First, you will need to download the set of libraries here. The one library required to control Wonder Workshop robots is called adafruit_ble. To install the library, open the downloaded zip file and copy the adafruit_ble directory into the CIRCUITPY/lib/ directory, where CIRCUITPY is the root directory of your Clue drive.

If/when you attach more sensors and peripherals to your Clue board, you may need to install more libraries to control those sensors and peripherals. We recommend keeping the zip file handy as you develop your Clue/Dash application, especially if it will require additional sensors or peripherals in the future.

Install Wonder Workshop’s module for controlling Dash/Cue, ‘wonder

Download the wonder module here here.

The zip file contains a directory named “wonder”. Copy the entire “wonder” directory onto your Clue board into the directory <CIRCUITPY>/lib/ . You should now be able to use the wonder module on your Adafruit Clue Python programs.

Running Python Programs on the Adafruit Clue

You are now ready to write and run Python programs on your Adafruit Clue. You may use any basic text editor, such as Microsoft Notepad, to edit your Python programs, but we recommend using a real code editor. Many are available for free, such as the Sublime Code Editor.

To run code on the Adafruit Clue, you will need to edit or create a file called “code.py” on the Adafruit Clue. You may do this any number of ways, but we recommend that you create and edit your “code.py” file on your PC and then copy it onto the Adafruit Clue’s “CIRCUITPY” drive. We recommend this method just in case the CIRCUITPY drive gets corrupted or if the Clue board gets damaged in any way, you will still have a copy of your code on your PC.

When the Adafruit Clue boots up or is reset, it will search for a Python file called “code.py” and attempt to execute it. If there are syntax or other errors during the execution of the file, the errors will be displayed on the Adafruit Clue’s built-in screen.

To run the programs in the next sections, copy the code contents into a file called “code.py”, attach your Adafruit Clue to your PC with a USB cable, and copy the file to the new drive that appears when the Adafruit is connected. The code will save onto the Clue and the Clue will run the program whenever it is powered up, even if it is not attached to a computer.

Write your first Clue+CircuitPython+Dash program

We are now ready to try our first Python program that controls Dash. We will first present a complete code sample and then describe each line in detail. Here is a simple program which makes Dash drive 30cm forward and then performs a 360-degree spin to the right:

import wonder

robot = wonder.Dash('Dash')
robot.drive(30)
robot.turn(-360)

The first statement of the program, import wonder , imports the wonder module which contains the required classes and functions for controlling Wonder Workshop robots.

The next statement reads robot = wonder.Dash('Dash'). The expression wonder.Dash('Dash') finds and connects to a robot named ‘Dash’1 and creates a wonder.Dash object. The object is then saved to a variable named robot. The new robot variable contains a great many member functions that perform a variety of functions, including moving the robot’s wheels and head, controlling the robot’s LED lights, and reading data from the robot’s various sensors, such as the wheel odometers, IR rangefinders, accelerometer, and more.

The next statement, robot.drive(30), uses the drive() member function to make Dash drive 30cm forward. The argument value is in units of centimeters. Negative values make the robot drive backward.

The final statement, robot.turn(-360), make the robot turn in a complete circle in the clockwise direction as viewed from above the robot. The argument is in units of degrees and positive values make the robot turn counter clockwise.

1

Dash robots come from the factory with a default name of ‘Dash’. The robots may be renamed using the ‘wonder’ app, available on any smartphone.

wonder Module Documentation

class wonder.Dash(name='Dash', address=None, transport=None, enable_sensor0=True, enable_sensor1=True)

A class for controlling Dash and Cue robots.

This class contains a number of member functions to perform a variety of tasks related to Dash and Cue robots. These tasks include:

  • Moving the robot

  • Getting sensor information from the robot

  • Registering callback functions to be invoked when certain events occur.

Examples:

Moving the robot forward 20 centimeters:

import wonder
robot = wonder.Dash()
robot.drive(20)

Setting the left ear RGB LED to purple:

import wonder
robot = wonder.Dash()
robot.left_ear_led(255, 0, 255)

Very naive object following for 1 minute:

import wonder
import time
robot = wonder.Dash()
start_time = time.time()
while (time.time() - start_time) < 60:
    distance = robot.ir_distance_left()
    if distance > 20:
        robot.linear_angular(10, 0)
    if distance < 10:
        robot.linear_angular(-10, 0)
    else:
        robot.linear_angular(0, 0)
Parameters

name (str, optional) – Name of the robot to connect to. Defaults to “Dash”

add_button_1_cb(fn)

Add a function to be called whenever the button 1 is pressed.

add_button_2_cb(fn)

Add a function to be called whenever the button 2 is pressed.

add_button_3_cb(fn)

Add a function to be called whenever the button 3 is pressed.

add_button_main_cb(fn)

Add a function to be called whenever the main button is pressed.

Example:

import wonder

def my_func(button_down):
    if button_down:
        print('Main button pressed!')
    else:
        print('Main button released!')

dash = wonder.Dash('Dash')
dash.add_button_main_cb(my_func)
# Press Dash's main button now to trigger `my_func()`

# Spin the program forever so we can wait for button events
while True:
    wonder.sleep(1)

See also

wonder.sleep()

Parameters

fn (fn(bool)->bool) – A function of the form fn(button_down)->bool . If the return value of the callback function evaluates to “True”, it will not be called again.

Returns

Button handler id

Return type

int

drive(cm=10, time=1, wait=True)

Drive Dash forward or backward.

Drive the robot a certain distance in a desired amount of time. Negative distances make Dash drive backwards. Smaller ‘time’ values cause the robot to travel faster.

Example:

import wonder
dash = wonder.Dash('Dash')
dash.drive(50, 5) # Dash will drive 50cm forward in 5 seconds
Parameters
  • cm (float) – distance to travel (cm)A

  • time (float) – time to perform the motion (seconds)

  • wait (bool) – Wait for the motion to finish. If this is set to “False”, this function will return immediately. Otherwise, this function will block until the movement is finished.

front_led(red, green, blue)

Change Dash’s chest LED color.

get_accel()

Get Dash’s accelerometer readings

Returns

A list of three floats. Each number represents the current detected acceleration for axes X, Y, and Z in units of Earth G’s.

Return type

list

get_battery_info()

Get info regarding the battery.

The return value is a tuple in the form:

(battery_level, charge_status, usb_connected, battery_voltage)

‘battery_level’ is a float value between 0 and 1.

‘charge_status’ values map to the following:

0: Not charging 1: Pre charging 2: Fast charging 3: Done charging

‘usb_connected’ is a boolean value that indicates whether USB power is connected or not.

‘battery_voltage’ is a float value indicating the battery voltage in Volts

get_encoders()

Get Dash’s current encoder values

Returns

A list of two values representing the current odometry of the left and right wheels.

Return type

list

get_head_pan_angle()

Get Dash’s current head pan angle

A pan angle of 0 indicates Dash is looking straight forward. Positive values mean Dash is looking to the left, negative values mean Dash is looking to the right.

Returns

Dash’s head pan angle in degrees.

Return type

float

get_head_tilt_angle()

Get Dash’s current head tilt angle

Returns

Dash’s head tilt angle in degrees

Return type

float

get_ir_left()

Get Dash’s current front-left IR rangefinder reading.

Returns

an estimated distance in cm

Return type

float

get_ir_rear()

Get Dash’s current rear IR rangefinder reading.

Returns

an estimated distance in cm

Return type

float

get_ir_right()

Get Dash’s current front-right IR rangefinder reading.

Returns

an estimated distance in cm

Return type

float

get_pose()

Get Dash’s current pose estimate

Dash maintains a pose estimate based on wheel odometry and gyro integration. The internal pose estimate consists of an (x,y) coordinate and a orientation angle. Dash resets its internal pose estimate to (0,0,0) upon startup. The “set_pose()” member function may also be used to set Dash’s internal pose estimate.

Returns

A tuple of floats, (x_cm, y_cm, angle_degrees)

Return type

tuple

get_pose_watermark()

Get current length of Dash’s pose queue

get_voice_dir()

Get the direction of the last heard voice.

Returns

A tuple consisting of the direction in global degrees, a confidence value from 0 to 1, and a timestamp.

Return type

tuple

goto(x, y, degrees, time, motion_type=2, coord=2, wait=True)

Make Dash drive to a particular location and orientation.

This commands moves the robot from its current position to a relative position (x,y). The coordinate system is fixed to Dash’s body as shown in ascii image below:

        +X  (Forward)
         ^
         |         <-
         |            \
+Y <--- Robot  +Angle |
(Left)                /

For example, the following command will move Dash so that it ends up 10 centimeters forward and facing to the left:

import wonder
robot = wonder.Dash()
robot.goto(10, 0, 90, 1)

Similarly, the following command will make Dash move so that it ends up 10 centimeters to the right of its starting position:

robot.goto(0, -10, 0, 1)

Finally, the next command turns Dash in place 30 degrees to the right:

robot.goto(0, 0, -30, 1)
Parameters
  • x (float) – number of centimeters to move forward

  • y (float) – number of centimeters to move to the left

  • degrees (float) – Number of degrees counter-clockwise for the end position to be offset from the starting position.

  • time (float) – Number of seconds allotted to complete the action. Larger numbers result in slower movement.

  • wait (bool) – Wait for the motion to finish. If this is set to “False”, this function will return immediately. Otherwise, this function will block until the movement is finished.

  • motion_type – One of wonder.FORWARD, wonder.BACKWARD, or wonder.INFERRED. FORWARD forces the robot to travel in its relative forward direction to reach the destination, BACKWARD forces the robot to travel backward, and INFERRED picks the direction automatically depending on the relative position of the destination. INFERRED is default.

  • coord

    One of wonder.GLOBAL, wonder.REL_COMMANDED, wonder.REL_MEASURED (default), or wonder.TEMP_GLOBAL.

    • wonder.GLOBAL indicates that the specified x,y,angle coordinates are global coordinates. Dash sets its global pose estimate to (0,0,0) upon startup. The global pose estimate may also be set by wonder.Dash.set_pose().

    • wonder.REL_COMMANDED indicates that the specified coordinates are relative to the last commanded destination from the previous wonder.Dash.goto(), wonder.Dash.drive(), or wonder.Dash.turn() function call. When Dash/Cue are commanded to go to a certain destination, there may be some error/difference between the the robot’s actual final pose and the expected pose. Specifying wonder.REL_COMMANDED indicates that the new target destination should be calculated from the theoretical commanded position of the robot rather than the actual current position.

    • wonder.REL_MEASURED indicates that the destination coordinates should be calculated relative to the robots actual current estimated location.

    • wonder.TEMP_GLOBAL indicates that the destination coordinates are specified in a temporary global reference frame. See also: wonder.Dash.set_pose().

Note

This function may be “spammed” (called repeatedly with high frequency) to make the robot travel in smooth complex paths. Spamming at a period of 100ms-200ms is typically sufficient to make Dash drive smoothly along complex paths. Just ensure that the time parameter is set to the same or similar period that this function is being called or the robot may jitter.

gripper_close()

Close the Gripper accessory

If there is a Gripper accessory attached to Dash, this function makes the gripper close.

gripper_open()

Close the Gripper accessory

If there is a Gripper accessory attached to Dash, this function makes the gripper open.

head_pan_angle(angle, time=0, hold_forever=False)

Pan Dash’s head left/right

Move Dash’s head to a left/right position.

Parameters
  • angle (float) – The desired head angle in degrees. An angle of “0” indicates straight forward. Positive values make Dash look left.

  • time (float) – Time interval to move to desired angle. Higher values make Dash move its head slower.

  • hold_forever (bool) – If set to true, Dash will actively maintain the desired head angle even if there are outside forces acting on Dash’s head.

head_pan_voltage(power)

Apply motor power to Dash’s head pan motor

This function will apply constant power to Dash’s head pan motor, regardless of the current head angle.

Parameters

power (int) – A value from -100 to 100

head_tilt_angle(angle, time=0, hold_forever=False)

Tilt Dash’s head up/down

Parameters
  • angle (float) – The desired head angle in degrees. An angle of “0” indicates straight forward. Positive values make Dash look up.

  • time (float) – Time interval to move to desired angle. Higher values make Dash move its head slower.

  • hold_forever (bool) – If set to true, Dash will actively maintain the desired head angle even if there are outside forces acting on Dash’s head.

head_tilt_voltage(power)

Apply motor power to Dash’s head tilt motor

is_stopped()

See if Dash is moving or not

Return type

bool

launcher_launch(power)

Launch a ball with the Launcher accessory

This function makes Dash launch a ball with the Launcher accessory.

Parameters

power (int) – A power value between 1 and 100

launcher_load(left=True)

Load the Launcher

This function is meant to be used with the Launcher accessory. Calling this function will load from either the left or the right side, depending on the “left” argument.

Parameters

left (Bool) – If set to true, load from the left side. Otherwise, load from the right side.

left_ear_led(red, green, blue)

Change Dash’s left ear LED color

Example:

# Turn Dash's left ear LED to a bright purple color
import wonder
dash = wonder.Dash('Dash')
dash.left_ear_led(255, 0, 255)
Parameters
  • red (int) – Intensity of red channel (0-255)

  • green (int) – Intensity of green channel (0-255)

  • blue (int) – Intensity of blue channel (0-255)

linear_angular(lin_vel=10, ang_vel=0)

Make Dash begin driving forward/backward/turning

This function causes Dash to start driving at a certain speed and turn speed forever until another drive command is received.

Example:

Make Dash travel forward at 20cm/s for 5 seconds

import wonder
dash = wonder.Dash('Dash')
dash.linear_angular(20, 0)
wonder.sleep(5)
dash.stop()

Note

The previous example may not move the robot exactly 20*5=100cm due to inaccuracies in timing. If precise distance is required, use the wonder.Dash.drive() or wonder.Dash.goto() methods.

Parameters
  • lin_vel (float) – Linear velocity in cm/s. Negative values cause Dash to begin rolling backward.

  • ang_vel (float) – Angular velocity in deg/s. Positive values make Dash turn left at ang_vel deg/s.

move_wait()

Block until Dash has stopped moving

This function will “block” until Dash has stopped moving.

The following example performs a number of steps. First, Dash is commanded to drive 50 centimeters forward. Because the “wait” keyword argument is set to “False”, the “dash.drive()” function immediately returns and the next statement is executed. The next statements make Dash turn its head right, and then left, while Dash is still moving. Finally, the “dash.move_wait()” statement is executed which waits until Dash has stopped moving. Finally, after Dash has stopped moving, Dash is commanded to look straight forward.

Example:

import wonder
dash = wonder.Dash('Dash')
dash.drive(50, wait=False)
dash.head_pan_angle(-90)
dash.head_pan_angle(90)
dash.move_wait()
dash.head_pan_angle(0)
on_button_1(button_down)

Button handler for button 1.

on_button_2(button_down)

Button handler for button 2.

on_button_3(button_down)

Button handler for button 3.

on_button_main(button_down)

Button handler for Dash’s main button.

Override this function with your own. This function will be called any time the main button state changes, either being pressed or released. The “button_down” parameter will indicate the new button state. For instance, if the button is being pressed, “button_down” will be True. If it is being released, “button_down” will be false.

Example:

import wonder
import time
class MyDash(wonder.Dash):
    def on_button_main(self, button_down):
        if button_down:
            print('Button main pressed!')
        else:
            print('Button main released!')

dash = MyDash('Dash')
# Press the main button to trigger the custom callback

# Spin the program forever so we can wait for button events
while True:
    wonder.sleep(1)

See also

wonder.sleep()

play_audio_by_name(name)

Play an audio file by name.

Valid names are in the “sounds” submodule and include the following:

sounds.talk.HI 
sounds.talk.HUH 
sounds.talk.UH_OH 
sounds.talk.OKAY 
sounds.talk.SIGH 
sounds.talk.TADA 
sounds.talk.WEE 
sounds.talk.BYE 

sounds.funny.BEEPS 
sounds.funny.LASERS 
sounds.funny.GOBBLE 
sounds.funny.BUZZ 
sounds.funny.AY_YAI_YAI 
sounds.funny.SQUEAK 

sounds.animal.HORSE 
sounds.animal.CAT 
sounds.animal.DOG 
sounds.animal.DINOSAUR 
sounds.animal.LION 
sounds.animal.GOAT 
sounds.animal.CROCODILE 
sounds.animal.ELEPHANT 

sounds.transport.FIRE_SIREN 
sounds.transport.TRUCK_HORN 
sounds.transport.CAR_ENGINE 
sounds.transport.CAR_TIRE_SQUEEN 
sounds.transport.HELICOPTER 
sounds.transport.JET_PLANE 
sounds.transport.BOAT 
sounds.transport.TRAIN 

Example:

import wonder
dash = wonder.Dash('Dash')
dash.play_audio_by_name(wonder.sounds.talk.HI)
wonder.sleep(5) # Maintain connection with robot until sound is done playing
right_ear_led(red, green, blue)

Change Dash’s right ear LED color.

set_pose(x=0, y=0, theta=0, time=0.0, temporary=False)

Set Dash’s current pose estimate

Parameters

temporary (bool) – If true, instruct the robot to create a temporary global reference frame. See also: wonder.Dash.goto().

See also

Dash.get_pose()

sketchkit_pen_down()

Set the SketchKit pen down

If the SketchKit accessory is attached to your Dash robot, this method sets the pen down.

sketchkit_pen_up()

Set the SketchKit pen up

stop()

Immediately stop Dash’s motors

synth(freq, duration)

Make Dash play a synthesized sine wave (audio)

Parameters
  • freq (int) – A frequency in Hertz

  • duration (float) – A duration to play the sound is seconds

turn(angle, wait=True)

Make Dash turn in place

Make Dash turn in place. Positive values make Dash turn left. Use negative values to turn right.

Example:

import wonder
dash = wonder.Dash('Dash')
dash.turn(-45)
Parameters

angle (float) – Angle to turn (degrees)

wait_for_voice()

Make the program stop and wait until Dash hears a voice.

Returns

A tuple, (direction[global degrees], confidence (0.0,1.0), timestamp)

Return type

tuple

Example:

import wonder
dash = wonder.Dash('Dash')
direction, confidence, timestamp = dash.wait_for_voice()
print('Voice detected in direction: {} with confidence: {}'.format(direction, confidence))
dash.goto(0, 0, direction, 2, coord=wonder.GLOBAL)
class wonder.DashTerminal(*args, **kwargs)
wonder.sleep(seconds)

Pause the program for some time.

On the Adafruit Clue and other CircuitPython implementations, this sleep function is preferred over time.sleep() because it allows Dash to continue emitting/receiving sensor data in the background.

Parameters

seconds (float) – The number of seconds to pause

Indices and tables