Calico Myro Multiple Robots

From IPRE Wiki
Jump to: navigation, search

Introduction

It's possible to control multiple robots from one shell on one computer. This can open up a new world of amazing new opportunities in Calico.

Setup

Each Bluetooth adaptor can connect to up to 8 devices. One need only pair the device with each robot. You can then control each robot individually using the following interface.

Normally in Myro, you use the init() function followed by commands such as turnLeft(), such as the following example:

init("COM12")
turnLeft(1, 3)
turnRight(1, 3)

Using the individual robot interface, you can do the same thing:

robot = Scribbler("COM12")
robot.turnLeft(1, 3)
robot.turnRight(1, 3)

The advantage is that you can control multiple robots:


robot1 = Scribbler("COM12")
robot2 = Scribbler("COM13")

robot1.turnLeft(1, 3)
robot1.turnRight(1, 3)

robot2.turnLeft(1, 3)
robot2.turnRight(1, 3)

The rest of this page demonstrates this use.

Simultaneous Actions

By defining each robot as a variable, each robot can be controlled separately or together from one shell.

robot1=Scribbler("COM10")
robot2=Scribbler("COM20") 
robot3=Scribbler("COM30")

Each scribbler robot has been defined as a variable, robot1, robot2, robot3. Commands can be given using standard Myro syntax in the following format.

robot1.forward(1)
robot2.forward(.5)
robot3.forward(.75)
wait(5)
robot1.stop()
robot2.stop()
robot3.stop()

This code will allow robot1 to move at a speed of one, robot2 to move at a speed of 0.5, and robot3 to move at a speed of 0.75 simultaneously for five seconds. The robots do not have to move synchronously, they can move individually at separate times. For example,

robot1.forward(1,5)
robot2.forward(1,3)
robot3.forward(1,1)

Including times after the speed in the parenthesis allows each robot to move one after the other. In this case robot1 would move at a speed of one for five seconds, then robot2 would move at a speed of one for three seconds, finally robot3 would move at a speed of one for one second.

All commands will be performed in the order given when a run time is specified for each robot individually, if not the robots will respond simultaneously.

Example

This file allows 4 scribblers to do an "elephant dance"

# Fancy Elephant dance
# For four robots. The robots start out dancing in synch and then
# move to mirror image dancing
# Authors: Tara Crittenden, Eva Guido, Nick Iltchenko, Nick Persicketti
from Myro import *
# Set up four robots (on ports com41 - com 44
robot1=Scribbler("com41")
robot2=Scribbler("com42")
robot3=Scribbler("com43")
robot4=Scribbler("com44")
# ---------- runMotors --------
#
# Control all 4 robots left and right motors for waittime w
# the four robots all do this function in synch
def runMotors(l, r, w):
   robot1.motors(l,r)
   robot2.motors(l,r)
   robot3.motors(l,r)
   robot4.motors(l,r)
   wait(w)
   robot1.stop()
   robot2.stop()
   robot3.stop()
   robot4.stop()


# ---------- turn 1 -----------------
#
# Robots 1&2 are in unison turning left, robots 3&4 are in
# unison turning right
# variables defined as s = speed, t = time for rotation,
# w = delay between turn1 and its following action.


def turn1(s, t,w):
   robot1.turnLeft(s)
   robot2.turnLeft(s)
   robot3.turnRight(s)
   robot4.turnRight(s)
   wait(t)
   robot1.stop()
   robot2.stop()
   robot3.stop()
   robot4.stop()
   wait(w)
# ---------- turn 2 -----------------
#
# Robots 1&2 are in unison turning right, robots 3&4 are in
# unison turning left
# variables defined as s = speed, t = time for rotation,
# w = delay between turn1 and its following action.


def turn2(s,t,w):
   robot1.turnRight(s)
   robot2.turnRight(s)
   robot3.turnLeft(s)
   robot4.turnLeft(s)
   wait(t)
   robot1.stop()
   robot2.stop()
   robot3.stop()
   robot4.stop()
   wait(w)
# ---------- turn 3 -----------------
#
# Robots 1&2 are turning left, robots 3&4 are
# turning right
# *** you will notice as time for rotation has been specified
#       in each robot's turn, they will move in order but at
#       separate times.
# variables defined as s = speed, t = time for rotation,
# w = delay between turn1 and its following action.


def turn3(s,t,w):
   robot1.turnLeft(s,t)
   robot2.turnLeft(s,t)
   robot3.turnRight(s,t)
   robot4.turnRight(s,t)
   wait(w)
# -------- fan ---------
# this function allows the robots to rotate in a circle formation
# around each other.   This is done through the use of separate speed
# and direction for each robot.
def fan():
   robot1.motors(.7,.1)
   robot3.motors(-.1,-.7)
   robot2.motors(1,.7)
   robot4.motors(-.7,-1)
   wait(21)
   robot1.stop()
   robot3.stop()
   robot2.stop()
   robot4.stop()
#-----elephanttrain----
# when this function is run with robots in order as shown in the
# following line with all robots facing inward
# the robots will run in a synchronized routine
#
#  robot2, robot 1                  robot3, robot4


def elephanttrain():
   fan()
   turn1(1,.6,0)
   runMotors(1,1,5)
   wait(8)
   runMotors(1,1,5)
   turn3(1,0.7,1.5)
   turn2(1,0.7,0.5)
   runMotors(-1,-1,0.5)
   runMotors(1,1,0.5)
   turn1(1,.7,.5)
   runMotors(-1,-1,1)
   runMotors(1,1,1)
   runMotors(1,0.4,5)
   turn2(-1,0.7,0.5)
   runMotors(-1,-1,0.5)
   runMotors(1,1,0.5)
   turn1(-1,.75,.5)
   runMotors(.4,1,5)

Advanced

This section needs to be tested to make sure this really works! You need a current Calico to use all of the variations.

Myro also defines the doTogether() function which allows running code in parallel. For example, in the above examples we initialized the robots using:

robot1=Scribbler("com41")
robot2=Scribbler("com42")
robot3=Scribbler("com43")
robot4=Scribbler("com44")

This actually initializes the robots in sequence, one at a time. Rather, one can do the following:

robots = doTogether(Scribbler, ["com41", com42", "com43", "com44"])

In this example, Myro initializes them all simultaneously, and should start faster than initializing each at a time.

The general format of doTogether is:

results = doTogether(function(s), argument(s))

You can then access each robot in the returned list robots:

robots[0].forward(1, 2)
robots[1].forward(1, 2)
robots[2].forward(1, 2)

However, that moves each robot in sequence. If you wanted to move them together, then you could:

robots[0].forward(1)
robots[1].forward(1)
robots[2].forward(1)
wait(2)
robots[0].stop()
robots[1].stop()
robots[2].stop()

Or, even easier:

def moveEm(robot):
    robot.forward(1, 2)

doTogether(moveEm, robots)

You can also use "anonymous functions" (functions without names) by using the lambda keyword. The above example becomes:

doTogether(lambda robot: robot.forward(1,2), robots)

In this example, "lambda robot: ..." defines a function, just like moveEm, but doesn't name it and places it right inside the call to doTogether. Anonymous functions have many limits in Python, however, so it is often easier to just define it as with moveEm.

doTogether() has many variations, and they can all be used to coordinate your robots. For more information, see Calico Myro#Parallel_Code.