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.
Download the CircuitPython 7.0.0 image here.
Attach your Adafruit Clue to a PC computer with a Micro-USB cable.
Double-click the reset button on the back of the Adafruit Clue. It should now show up as a drive called “CLUEBOOT”.
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.
See also
- add_button_2_cb(fn)¶
Add a function to be called whenever the button 2 is pressed.
See also
- add_button_3_cb(fn)¶
Add a function to be called whenever the button 3 is pressed.
See also
- 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
- 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.
See also
- 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
, orwonder.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), orwonder.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 bywonder.Dash.set_pose()
.wonder.REL_COMMANDED
indicates that the specified coordinates are relative to the last commanded destination from the previouswonder.Dash.goto()
,wonder.Dash.drive()
, orwonder.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. Specifyingwonder.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
See also
- 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()
orwonder.Dash.goto()
methods.See also
- 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.
See also
- on_button_2(button_down)¶
Button handler for button 2.
See also
- on_button_3(button_down)¶
Button handler for button 3.
See also
- 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
- 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.
See also
- 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
- 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