Myro Reference Manual

Myro is a new framework for programming robots. It is written in the language Python and designed for use in Introductory Computing courses. It is being developed by the Institute for Personal Robots in Education.

THIS IS AN OLDER REFERENCE PAGE

This is for the old CPython myro API. For the new, Calico-based system, please see Calico Myro.

Reading Sensors

getLight(pos): read a light sensor on the scribbler; defaults to "all"

getIR(pos): read an IR sensor on the scribbler; defaults to "all"

getLine(pos): read line sensor on the scribbler; defaults to "all"

getStall(): read stall sensor on the scribbler

NOTE: Every time you issue a move command, the stall sensor resets, and it needs to wait a short time to see whether the motors are stalled. This means that the sensor won’t give accurate results if you test it too soon after the robot starts to move.

getName(): read the robot's name

getPassword(): read the robot's password

getAll(): read all positions of all of the major sensors; returns a dictionary

getObstacle("left" | "middle"| "center" | "right" | 0 | 1 | 2): read one of the Fluke's IR obstacle sensors (see setIRPower below). Higher values mean that IR light is being reflected (e.g an obstacle is detected), a low value means IR is not being reflected and there seems to be open space in that direction. The value ranges from 0 to 6400.

getBattery() gets the voltage of the battery (note: If the battery drops below ~6.1V the Fluke's back LED will flash to alert you to change or preferably recharge your batteries)

get(sensor): read the sensor "stall"; or get all readings of "ir", "light", or "line"; or get "all" which is all of those. Also can get "config".

get("config"): returns meta data about the robot's hardware

get(sensor, pos): read any of the following sensors or items by name and position

setData(position, value): set a byte of data in the robot's memory to a value between 0 and 255.

setLEDFront(value): turn on the led on the front of the Fluke (0 for off and or 1 for on)

>>> setLEDFront(1) # turn on the Fluke's front LED
>>> setLEDFront(0) # turn off the Fluke's front LED
>>> set("led", "front", 0) # turn off the Fluke's front LED

setLEDBack(value): turn on the LED on the back of the Fluke. The brightness of this LED is configurable between 0-1.

>>> setLEDBack(0.5) # turn on the Fluke's back LED at 1/2 brightness
>>> setLEDBack(1.0) # turn on the Fluke's back LED at full brightness
>>> set("led", "back", 0) #turn off the Fluke's back LED

setIRPower(power): set the output power of the Fluke's IR obstacle sensors (defaults to 135). If getObstacle() always reports high values try lowering the IR output power. If you always receive a zero value, try increasing the power. The power value should be between 0 and 255.

>>> setIRPower(135)
>>> setIRPower(140)

darkenCamera(level): turn off the camera's auto-exposure, auto-gain, and lower the gain to "level:. This is useful
when using the getBright() virtual light sensors.

manualCamera(gain=0, brightness=128, exposure=65): turn off the camera's auto-exposure, auto-gain, and auto-white balance, and set the gain (integer in the range 0-63), brightness (integer in the range 0-255), and exposure manually (integer in the range 0-255). (In version 2.8.3 of myro)

autoCamera(): turn on the auto-exposure, auto-gain, and auto-color-balance.

Flow of Control

If you wished to perform a loop for 5 seconds, you could use one of the two following idioms:

while timeRemaining(5):
print "running..."

for seconds in timer(5):
print "running for", seconds, "..."

loop(function1, function2, ..., count) - a simple looping system so
students can do a function a fixed number of times. loop() also stops
the robot at the end.

Image processing

The following objects and functions are related to the camera functions on the Scribbler. There are two different interfaces: the Multimedia interface (largely based on Mark Guzdial's introductory book), and the Graphics Object interface (largely based on John Zelle's introductory book). These are independent; however, there are methods to move between the two. The first library is built on the second.

The show(picture) function has a couple of mouse functions. You can click with the left mouse on a pixel and you can see "(x,y): (r,g,b)" in the window's status bar. If you click and drag a rectangle in the window, you will set the blob-tracking colors to the ranges of colors inside the bounding box.

Note that as of Myro version 2.9.0, the Image class constructor can accept a picture (as created by the makePicture() function) directly, allowing the above code to be replaced with:

win = GraphWin(title)
p = Point(x,y)
image = Image(p, picture)

All types of images have an RGB value, even if an image type actually has a palette (such as gif files), or grayscale images. Images that have a palette will use the palette entry for getColor(), and will look-up the closest color in the palette when using setColor(). For example, if you try to set a pixel to Color(255, 255, 255) but there is no such color in the palette, then the color will be set to a nearby color. Gray scale images will have identical RGB values for each pixel. For example, getColor(getPixel(p, x, y)) might give Color(125, 125, 125) for one position and Color(65, 65, 65) for another. When setting a color in a grayscale image, the single value is actually taken as the average of the 3 components. For example, if you tried:

The color of that pixel would end up at 100, (50 + 100 + 150)/3 = 100.

If you wanted to actually make part of a grayscale image a color, then you would need to turn the grayscale into a color image, via something like:

# take a grayscale picture:
p = takePicture("gray")
# make a new color picture the same size:
colorPic = makePicture(getWidth(p), getHeight(p))
# go through each pixel and copy it to new color picture:
for p in getPixels(picture):
setColor(getPixel(colorPic, getX(p), getY(p)), getColor(p))

You can also save any picture to a file:

writePictureTo(picture, filename) # for compatibility with Mark Guzdial's book
savePicture(picture, filename) # does the same as above, but has intuitive name

Examples

Processing by rows and cols:

from myro import *
picture = makePicture(pickAFile())
show(picture)
for i in range(getWidth(picture)):
for j in range(getHeight(picture)):
pixel = getPixel(picture, i, j)
setGreen(pixel, 255)
repaint() # not every time, just once per col

Advanced Vision Functions

The Fluke can not only take images, but it can do some very simple image processing. In particular, a simple form of on-board image segmentation. If you want to track something in an image based on its color or brightness, the on-board color segmentation can be very useful since its faster than doing it in python. By default, the Fluke is set to track pink objects. You can also graphically select an object in the image to track. First use the show(picture) function and then drag a box around the object you want to track, the software will automatically determine the color bounding box.

We can use the Fluke's computer vision in two ways. First, we can grab a "blob" image from the Fluke. This image is a black and white image with the white pixels being part of the object of interest. Blob images can be transmitted faster than a full color picture.

The parameters to configureBlob() create a bounding box in YUV space. Instead of using RGB which stands for Red/Green/Blue, YUV is an alternate way to describe color. The Y component contains the brightness or intensity information of the pixel, the U/V components contain the color.

Finally, you can also use getBlob() to locate bright pixels. We do this by segmenting bright pixels, meaning the Y components of the pixels are large :

Note: When initially created, the graphics window coordinates range from 0,0 (upper left corner) to width-1, height-1 (lower right corner). This function can be used to change the coordinates of the window (so, for example, it ranges from 0,0 to 1,1, or, to position the origin at the center, from (-1,
-1 to 1,1). Note that you may need to undraw and redraw objects after a coordinate change.

Once you have a graph window created you can draw the following Graph Objects on it with their .draw() method:

Miscellaneous commands

wait(seconds) - Pause for the given amount of seconds. Seconds can be a decimal number.

>>> wait(5)
>>>

currentTime() - the current time, in seconds from an arbitrary starting point in time, many years ago. Can you figure out the date of the start time?

>>> currentTime()
1164956956.2690001

makeStory() - A type of MadLibs system for making up stories that get
their variables (noun1, verb2, etc) filled in by the user. Myro will
read back their story. Enter variables() in Myro to see a couple of
examples.

numberGame() - A High-Low number-guessing game where the students learn
to divide and conquer to guess a number.

odd(n) - returns True if n is odd

even(n) - returns True if n is even

Random decisions

flipCoin() - Returns "heads" or "tails" randomly.

>>> flipCoin()
'tails'
>>> flipCoin()
'tails'
>>> flipCoin()
'heads'

heads() - returns True 50% of the time

tails() - returns True 50% of the time

pickOne(value) or pickOne(value1, value2, ...) - Returns a number or element randomly. New in Myro 1.0.2

saveSong(text or song, filename) - saves a song in tuple format, or in text format

playSpeech(filename) - play a WAV file

saveSpeech(message, filename) - save the message as a WAV file

Web development

In order to use the web development you first need to run the register() function. You will need to enter the fields as below:

Your email address : (your email address)
Your robot's name : (any name up to 16 characters, no spaces or other punctuation)
Course keyword : owls OR yjackets OR yellowj
Create a Myro password: (any password, don't use a good one, but it is encrypted)

Gamepad Details

getGamepad("count") - returns (immediately) the number of gamepads connected

getGamepad(ID, ITEM, ...) - return the ITEMs for gamepad ID. ID can be left out and will default to 0, the first one. If you request more than one ITEM, then they come back in a dictionary. Just request one ITEM and you'll get the value (as a list, string, or number).

getGamepad([ID1, ID2...], ITEM, ...) - return the ITEMs for gamepad IDs as a list of lists of ID, RESULTS. For example:

The window produced with the show(picture) command allows mouse clicks. The clicks will display the (x,y) and (r,g,b) in a status bar. Drag a rectangle to set YUV ranges for blob-tracking.

getPixels() returns a generator object. Therefore, you cannot get a pixel by index.

The Myweb webpages give some notes. The images that a user has will be available when he/she edits their page. Images are placed in /myweb/data/robotname/*.jpg. Therefore one can:

sendPicture(takePicture(), "my-house", "PassWoRDz") # assumes robot is connected, to take picture and get name
sendPicture(takePicture(), "my-house", "PassWoRDz", "kitty") # you can provide the name explicitly, also

There is also a RemoteRobot constructor which acts like a regular robot, but sends the commands to the other robot.

>>> robot = RemoteRobot("remoterobotname")
>>> robot.turnLeft(.4)

Robot's Orientation

If you are using a bluetooth-serial adapter or a serial cable to control your robot, then the scribbler's normal forward direction is used. When using the Fluke the forward direction is flipped. "Forward" is in the direction of the Fluke's camera. However, the orientation of the scribbler can be manually changed using the setForwardness() function. This is particularly useful if you want to use the Scribbler's IR and light sensors.

setForwardness(orientation): orientation can be 0/"scribbler-forward" or 1/"fluke-forward"

getForwardness(): Returns the orientation of the robot "scribbler-forward" or "fluke-forward"