Make A Mind Controlled Arduino Robot
Make A Mind Controlled Arduino Robot
Mind-
Controlled
Arduino
Robot
Tero Karvinen and Kimmo
Karvinen
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online
editions are also available for most titles (http://my.safaribooksonline.com). For more
information, contact our corporate/institutional sales department: (800) 998-9938 or
[email protected].
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks
of O’Reilly Media, Inc. Make a Mind-Controlled Arduino Robot and related trade dress are trade-
marks of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are
claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc.,
was aware of a trademark claim, the designations have been printed in caps or initial caps.
Important Message to Our Readers: The technologies discussed in this publication, the limi-
tations on these technologies that technology and content owners seek to impose, and the laws
actually limiting the use of these technologies are constantly changing. Thus, some of the projects
described in this publication may not work, may cause unintended harm to systems on which
they are used, or may not be consistent with current laws or applicable user agreements.
Your safety is your own responsibility, including proper use of equipment and safety gear, and
determining whether you have adequate skill and experience. Electricity and other resources
used for these projects are dangerous unless used properly and with adequate precautions, in-
cluding safety gear. These projects are not intended for use by children. While every precaution
has been taken in the preparation of this book, O’Reilly Media, Inc., and the authors assume no
responsibility for errors or omissions. Use of the instructions and suggestions in Make a Mind-
Controlled Arduino Robot is at your own risk. O’Reilly Media, Inc., and the authors disclaim all
responsibility for any resulting damage, injury, or expense. It is your responsibility to make sure
that your activities comply with applicable laws, including copyright.
ISBN: 978-1-449-31154-4
[LSI]
1323797765
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
2/Coding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Moving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Connect Servos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22
Hello Servo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25
Calibrate Stopping Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Full Speed Forward . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26
Other Ways to Control Servos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27
Line Avoidance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Connect the Reflection Sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Hello Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30
Don’t Cross the Black Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Battery, No Strings Attached . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Choosing Rechargeable Batteries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Connecting the Battery and Power Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Bells and Whistles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38
Contents iii
Red, Green, and Blue LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Beeping Piezo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Setting Threshold with a Potentiometer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Everything But Your Mind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Code Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Measuring Your Brains with MindWave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Hack MindWave Dongle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Level Conversion with Resistors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .53
Hello Attention! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
NeuroSky Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Complete Mind-Controlled Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
iv Contents
Preface
Shortly, you will build your own mind-controlled robot. But that’s just the
beginning of what you’ll be able to do. As you follow the explanations for
components and codes, you will thoroughly understand how your robot
works. You can keep applying the knowledge to your own robots and EEG-
based prototypes.
You’ll learn to
• Connect an inexpensive EEG device to Arduino
• Build a robot platform on wheels
• Calculate a percentage value from a potentiometer reading
• Mix colors with an RGB LED
• Play tones with a piezo speaker
• Write a program to avoid lines (tracks)
• Create simple movement routines
were running the MindWave software and our own Python program on the
computer.
Maker Faire was great. Arduino was clearly the platform of choice for hard-
ware hackers. There were Arduino robots that could dive and others that
could fly. So did we stand a chance of getting any attention to our little bot?
vi Preface
Reactions
“It’s a fake!” Our favorite reaction was disbelief, as it showed that EEG tricks
were still new. As if what we were doing was so amazing that it simply had to
be just a magic trick. We only heard this about five times, though.
Most of the users simply thought the project was cool. Some were a little
skeptical at first, but trying is believing. About 300 visitors tried the device
and many more were watching (see Figure P-3 and Figure P-4).
Figure P-3. Robot at Maker Faire 2011, San Francisco Bay area.
We were surprised that it could work in a setting like that. Our prototype
could handle hundreds of visitors. Also, the NeuroSky EEG headband was
easy to put on and didn’t need any user training.
A couple of visitors had probably played with EEG before. They just noted
“Yep, it’s a NeuroSky” and started talking about something else. Luckily,
Brian Jepson had made a 3D-printed version of the soccer bot, so we had a
backup gadget to amuse them.
Preface vii
Figure P-4. Attendees control our robot at Maker Faire.
voltages (1–100 µV on the scalp). EEG doesn’t read your thoughts, but it can
tell your general state. For example, EEG can show if you are paying attention
or meditating.
The tiny voltages are easily masked by electrical noise from muscles and
ambient sources. EEG currents are measured in microvolts (µV), which are
millionths of a volt:
1 µV = 0.001 mV = 10-6 V
Noise from muscle and eye movement can be quite powerful compared to
this. In normal buildings, the electrical main’s current radiates a 50Hz or
60Hz electromagnetic field. In a laboratory setting, EEG is usually measured
in a room that has less interference. At home, the EEG unit must filter out
the troublesome signals.
viii Preface
EEG devices used to be prohibitively expensive and annoying to connect,
and the data required expert knowledge to interpret. For many years, a
starting price for the cheapest EEG units was thousands of dollars. They
required conductive gel to connect. Having very clean hair and skin was rec-
ommended. Most units used at least 19 electrodes. EEG results were printed
on paper and doctors had to take a course to be able to analyze them.
Now EEGs are cheap, starting from $100 (USD). Devices are available in
shops and by mail order. Consumer-level EEG units are manufactured by
NeuroSky and Emotiv. (OCZ used to make a similar device.) With the Open-
EEG project, you can even build an EEG device yourself.
NeuroSky’s units are the cheapest option, starting from $100 for the Mind-
Wave (shown in Figure P-5). The headband is fast to attach and works on
dry skin without any gels. It only needs electrical contact on your forehead
and earlobe. NeuroSky devices measure attention and meditation as well as
the raw brainwave data.
Preface ix
OCZ used to make the mOCZ Neural Impulse Actuator (shown in Fig-
ure P-6), which cost about $100. It made multiple measurements, mostly
concentrating on muscle activity.
Figure P-6. Haaga-Helia student project with OCZ Neural Impulse Actuator.
The OpenEEG project provides instructions on how to build your own EEG
device. It’s the most expensive option, costing about $400. Building the de-
vice requires both technical skills and understanding of safety issues. After
all, EEG involves connecting wires on different sides of your head!
NeuroSky MindWave
In the mind-controlled robot presented by this book, a NeuroSky MindWave
is used to measure attention. For about $100, you get a CD-ROM, a head-
band, and a USB dongle for the wireless connection.
The headset has a single electrode with a ground and reference. This means
that there are two metallic things touching your head. The measuring elec-
trode goes on the left side of your forehead. In the EEG lingo, this point is
called Fp1. It’s F for frontal, followed by p1 (1, the first odd number, indicates
10% to the left of your nose; 2, the first even number, indicates 10% to the
right of your nose). The other electrode, reference point, goes to your left
ear (A1). The headset measures the voltage between these two electrodes.
x Preface
The CD-ROM that comes with the MindWave contains software to be used
with the headband. It can show you attention level, meditation level, and
connection quality. You first place the electrode on your head and adjust
until the connection is good (the poorSignal value will be shown as 0).
When you focus on something, your attention level (0–100%) goes up. You
can do some math, read something, or just concentrate on your fingertip.
When you relax, your meditation level goes up. For example, you can close
your eyes and take deep breaths. If you can calm and focus your mind at the
same time, both attention and meditation can go up to 100%.
The USB receiver dongle can be hacked to connect directly to Arduino.
Preface xi
Running Ubuntu Linux? Starting from Ubuntu
11.04, you can sudo apt-get install arduino. For
other distributions of Linux, see http://www.ardu
ino.cc/playground/Learning/Linux.
You should have basic mechanical building skills. You’ll solder wires to an
RGB LED and your own connections to MindWave. To build the robot plat-
form, you’ll need to drill some holes. For soldering, see MABG, “Soldering
Basics” (page 47). For drilling, see MABG, “Building a Frame for the Robot”
(page 217).
Acknowledgments
We would like to thank:
• Haaga-Helia
• Tansy Brook, NeuroSky
• Valtteri Karvinen
• Nina Korhonen
• Marianna Väre
xii Preface
TIP: This icon signifies a tip, suggestion, or general
note.
Preface xiii
O’Reilly Media has uploaded this book to the Safari Books Online service. To
have full digital access to this book and others on similar topics from O’Reilly
and other publishers, sign up for free at http://my.safaribooksonline.com.
How to Contact Us
Please address comments and questions concerning this book to the
publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any
additional information. You can access this page at:
http://shop.oreilly.com/product/0636920021780.do
To comment or ask technical questions about this book, send email to:
[email protected]
For more information about our books, courses, conferences, and news, see
our website at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
xiv Preface
1/Building the Chassis
Before programming anything, we’ll build the chassis for the robot. Basically
it’s a traditional rover robot structure with two servo motors in the front and
one caster in the back. To make it suitable for mind-controlling needs, we’ll
add a line detector and RGB LED on the top. We use a solderless breadboard
and the ScrewShield for the Arduino, to make adding components and wires
easy. Figure 1-1 shows the design of the chassis.
Here’s how all the major components will work together to create a working
robot:
Arduino
This is the brains of the project. It is essentially a small embedded com-
puter with a brain (a microcontroller), as well as header pins that can
connect to inputs (sensors) and outputs (actuators).
Chassis
This holds everything together. It’s essentially the platform for the
robot.
Servo Motors
These are motors that can be connected directly to the Arduino without
the need for any additional hardware (such as a motorshield). The Ar-
duino communicates with them by sending pulses to control speed and
direction.
Caster wheel
Because we’ll be turning the robot by varying the speed and direction
of the servos, which are fixed in place, we need one wheel that pivots
nicely. A furniture caster is perfect for this, and the robot ends up being
able to rotate in place.
RGB LED
This component changes color and tells you what is happening in the
code, so you don’t have to divide your attention between the serial mon-
itor and the robot. It also gives instant feedback for the users when they
try to move the robot by focusing.
Line Detector
With the line detector, your robot will avoid a black line, which makes it
stay in the arena (helpful for keeping it from falling off a table).
1
Figure 1-1. Blueprint of the chassis
ScrewShield
ScrewShield adds “wings” with terminal blocks to both sides of Arduino.
Terminal blocks have screws, so you can attach one or more wires firmly
to any pin. This prevents wires from popping out, which makes building
and coding the robot much easier.
MindWave
MindWave measures your brainwaves and transmits the results for the
Arduino. We have to hack the MindWave dongle a little bit because we
want to connect it directly to Arduino instead of a computer’s USB port.
Parts
Figure 1-2 shows all the parts you need for this project.
2. Rechargeable battery (we used a DualSky 1300 mAh 30C 2s1p 7.4 V
battery)
3. Velcro
4. NeuroSky MindWave
5. Continuous rotation servos (we used Parallax [Futaba] Continuous Ro-
tation Servo) (2)
6. ScrewShield
7. Aluminum pipe, 8 mm thick, at least 60 mm long
8. Connection wire for the line-detecting sensor
9. RGB LED, common anode
10. Line-detecting sensor (we used DFRobot’s Line Tracking Sensor for Ar-
duino)
11. Potentiometer (rotary, linear resistance); choose one that can be easily
inserted into a breadboard (we used one with maximum resistance of
about 10 kOhm)
12. Power switch (any two-state switch will do)
13. Furniture wheel (caster) with ball bearings
Tools
Figure 1-3 shows all the tools you need for this project.
Servo Motors
Servo motors (Figure 1-4) will be moving the wheels of our robot. The most
usual type of servos have limited rotation. They are used when you need to
turn the motor to a specific angle. In our robot, we only need to control speed
and direction. And, of course, the motor needs to be able to turn freely. Con-
tinuous rotation servos are made for this. Almost any servo can be modified
to continuous rotation, but it’s easier to buy a ready-made version.
The Parallax (Futaba) continuous rotation servo is perfect for our needs. It
has an external potentiometer adjustment screw, which allows identical
centering of two servos effortlessly. You’ll notice how handy this is later,
when we program the movements for the robot.
Attaching Servos
We’re going to use regular L-brackets to attach the servos. Attach two
brackets to each servo with 3x10 mm screws, as shown in Figure 1-5.
If you can’t find suitable L-brackets, you can make them from metal strips.
For example, you could salvage some strips from an old typewriter, drill holes
that match your servo, and bend them to a 90° angle in the middle.
Chassis
For the chassis you’ll need something that is robust enough to hold the robot
together and can be shaped easily. Plywood, acrylic, or metal plate (Fig-
ure 1-6) works well.
Figure 1-12. 3 cm piece of aluminum pipe for the line-detecting sensor and a
felt pad to prevent short circuits
Put a 3x42 mm screw through the pipe and secure the line detector in the
front of the robot (Figure 1-13). The emitter/receiver part of the sensor has
to be facing down.
Wheels
There’s plenty of choice for the wheels (Figure 1-14). Just don’t pick any that
are too heavy, and make sure that you’ll be able to make the holes for the
servo horn attachment. For our robot, we salvaged tires from a remote-
controlled car.
Drill two 3 mm holes through both servo horns and the wheel rim. Secure
the servo horns to the wheel rims with 3x10 mm screws. Push the servo horns
on the servo shaft and tighten them in place with 3x18 mm woodscrews
(Figure 1-15).
Figure 1-15. Servo horn attached to the tire rim and wheel attached to the
servo
Attaching Arduino
Before attaching the Arduino to the robot, cover the bottom of the Arduino
with a self-adhesive felt pad (Figure 1-19). This will prevent short circuits that
could happen if the Arduino touched metal parts of the bot.
Figure 1-19. Felt pad on the bottom and Arduino screwed in place.
Battery Holder
Cut 14 cm strip from both sides of Velcro. Tape hooks and loops sides to-
gether and push or drill a hole in the middle. Put a 3x10mm screw through
the hole and mount the battery holder to the chassis (Figure 1-20).
Figure 1-20. 14 cm strips of Velcro attached into the bottom of the chassis
The code that controls your robot is simple. Well, it’s simpler than one would
expect for a sci-fi trick like mind control.
A simplified, pseudocode version of your robot would be as follows:
void loop()
{
while (lineDetected()) turn(); //
forward(getAttention()); //
}
The reflectivity sensor tells if the robot is on top of a black line, which
forms the border of the arena. When the robot is on the border, it turns
until the sensor sees white again.
Then the robot goes forward. The speed is read from the EEG headband.
Rinse and repeat.
In this coding part of the book, you’ll write each part of the code that makes
your robot tick.
Moving
Continuous rotation servos are motors you can easily control. With contin-
uous rotation servos, you can only control the speed (forward, stop, back),
but unlike standard servos, you can’t set the servo to point at a specific angle.
There are three wires going to a servo: red (positive), black (ground), and
white (data). To control a servo, you need to keep sending pulses to it. The
length of the pulse tells how fast the full rotation servo should turn. The pulse
length is very short, typically from 500 µs (microseconds) to 2000 µs. This
means it can be as little as half a millisecond: 500 µs = 0.5 µs = 0.0005
seconds.
To keep the servo turning, you must send these pulses about every 20 ms,
which is 50 times a second.
If you want a more through recap of how servos work, see the Insect Robot
chapter in Make: Arduino Bots and Gadgets (MABG) from O’Reilly (2011).
21
Connect Servos
Let’s start by connecting servos to Arduino. To keep the connectors in your
servos intact, use a servo extension cable to connect to Arduino. Cut the
male end of a servo extension cable. Strip wires from the end where you cut
off the connector (Figure 2-1).
Now connect the wires to Arduino. You can connect both the left and right
servo right away. As shown in the circuit diagram (Figure 2-5), the red (pos-
itive) wire goes to Arduino +5V and black (ground) goes to GND (Fig-
ure 2-2). The white data wires go to Arduino data pins D2 (digital pin 2) and
D3 (digital pin 3). Connect the left servo to digital pin D3 (Figure 2-3 and
Figure 2-4).
Coding 23
Figure 2-3. Connected to Arduino data pins; left servo goes to D3
void setup()
{
pinMode(3, OUTPUT); //
}
void loop()
{
digitalWrite(3, HIGH);
delayMicroseconds(2000); //
digitalWrite(3, LOW);
delay(10); // ms //
}
You must always set the pin mode; otherwise it stays in an undefined
state. OUTPUT means you can toggle the voltage of the pin: for example,
HIGH or LOW for digital pins. INPUT means you can measure whether a
pin is on or off.
This is the length of the pulse, the time the pin is HIGH.
It’s a good idea to use a comment to specify the units at least once in your
program. Millisecond is one thousand microseconds; i.e., 0.001 s = 1 ms
= 1000 µs.
Coding 25
The servo will still turn if we have a longer wait, such as 20 ms. But using 10
ms will make it easy to count times in your head. For example, 100 iterations
is 1000 ms = 1 s.
You can easily find this value and other specs from the data sheet. If you are
using the Parallax continuous rotation servos, you can find the data sheet at
http://www.parallax.com/dl/docs/prod/motors/crservo.pdf.
As you run the code, the servo will most likely crawl forward (because it is
not yet calibrated). Locate the calibration screw on the side of the servo.
Take your Phillips (crosshead) screwdriver and gently adjust the screw until
the movement stops.
Calibrate the other servo by changing the pin in helloservo.pde to 2.
void setup()
{
pinMode(servoLeftPin, OUTPUT);
pinMode(servoRightPin, OUTPUT);
}
void loop()
{
forward(); //
}
void forward()
{
for (int i = 0; i < 10; i++) { //
Coding 27
Line Avoidance
To make your bot stay in the arena, you must teach it to avoid a black line.
Then you can build an arena with big white paper as the floor and black tape
as the border.
Connect free sensor wires to Arduino as shown in the circuit diagram for
helloreflection.pde (Figure 2-7). Connect the red plus wire to +5V, and the
black ground wire to GND. Connect the green data wire to D4. (Figure 2-8).
Use the ScrewShield to keep the wires in place (Figure 2-9).
Coding 29
Figure 2-9. Free wires connected to Arduino with ScrewShield
Hello Reflection
For line avoidance, we use a typical reflectivity sensor. We read it with Ar-
duino’s digitalRead() function.
The value tells how much light is reflected back from the surface. It returns
HIGH (true, 1) for a white surface. Black doesn’t reflect light back, so the
sensor gives a LOW value (false, 0).
// hellorefelection.pde - turn led on if line detected
// (c) Kimmo Karvinen & Tero Karvinen http://MindControl.BotBook.com
void setup()
{
pinMode(tinyLedPin, OUTPUT);
pinMode(linePin, INPUT);
}
void loop()
{
if (LOW == digitalRead(linePin)) { //
digitalWrite(tinyLedPin, HIGH);
} else {
digitalWrite(tinyLedPin, LOW);
}
delay(20); //
}
We use the tiny surface-mounted LED that’s built into Arduino to show if
we’ve detected a line. The reflectivity sensor also has its own LED, so don’t
You already have all the knowledge to do this (in separate parts) from the
previous examples, so let’s combine them. Connect the servos and reflec-
tion sensor according to the circuit diagram for avoidline.pde (Figure 2-10).
Coding 31
// avoidline.pde - turn when black line seen
// (c) Tero Karvinen & Kimmo Karvinen http://MindControl.BotBook.com
void setup()
{
pinMode(linePin, INPUT);
pinMode(servoLeftPin, OUTPUT);
pinMode(servoRightPin, OUTPUT);
}
void loop()
{
while (lineDetected()) turn(); //
forward();
}
bool lineDetected()
{
return ! digitalRead(linePin); //
}
void forward()
{
for (int i = 0; i < 10; i++) {
pulseServo(servoLeftPin, 1500+500);
pulseServo(servoRightPin, 1500-500);
}
}
void turn() //
{
for (int i = 0; i < 30; i++) { //
pulseServo(servoLeftPin, 1500+500);
pulseServo(servoRightPin, 1500+500); //
}
}
Coding 33
Figure 2-11. Rechargeable lithium-polymer battery pack
The battery cable has a connector on one end and free wires on the other. It
connects the battery to the power switch and to Arduino GND. Use a
Figure 2-13. Putting heat shrink tubing on the cable for connecting battery to
Arduino and power switch
Coding 35
Figure 2-14. Adding a piece of heat shrink tubing before soldering to the
power switch
Coding 37
Bells and Whistles
LEDs and piezo speakers create user interface for many embedded devices.
Even though they are low-key compared to computer displays and big
speakers, they serve an important function. Users expect to get feedback
on what they are doing.
Using LEDs and speakers to describe program state also helps coding. It
would be difficult to keep a moving robot continuously on a USB leash.
Sounds and lights on the robot will tell you what’s happening, so you don’t
have to divide your attention between the serial monitor and the device. And
of course, you don’t have to fight with a lost serial connection.
The RGB LED you use in this project has one positive leg and three negative
legs. This configuration is called common anode. The positive wire is always
connected to Arduino’s +5V.
When your data pins (D9, D10, D11) are at +5V, there is no voltage difference
between the LED’s legs. All the LEDs are off.
When you want to light a LED, you set the pin to a low voltage. You can do
this with analogWrite(0). Now the data pin has 0V and common anode has
+5V, and the LED is lit.
Coding 39
Figure 2-20. Wires soldered to RGB LED
Connect the wires as shown in Figure 2-21. Common anode (common plus)
to Arduino +5V, and LEDs red to D9, green to D10, and blue to D11.
Hello RGB
// hellorgb.pde - Mix colors with RGB LED
// (c) Kimmo Karvinen & Tero Karvinen http://MindControl.BotBook.com
void setup()
{
pinMode(redPin, OUTPUT); //
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
}
Beeping Piezo
“Beep, beep!” Piezo beepers are everywhere: in cash registers, cameras—
even your PC speaker is one. A stream of on-off pulses makes a piezo
speaker vibrate, making air vibrate and thus making a sound. If you do it fast
enough you get a note. Our favorite note, A4, comes with 440 pulses a sec-
ond (440 Hz).
Coding 41
Push the piezo speaker into the breadboard on top of your robot. Piezos have
polarity: their positive side is usually marked with a plus (Figure 2-22). Con-
nect the positive side to Arduino digital pin D12, using a jumper wire with the
data wire color, like yellow, green, or blue. Connect the negative side to Ar-
duino GND with black jumper wire (Figure 2-23 and Figure 2-24).
Figure 2-22. Small plus marks the positive leg of piezo speaker
void setup()
{
pinMode(speakerPin, OUTPUT);
}
void loop()
{
wave(speakerPin, 440, 500); //
delay(50); //
wave(speakerPin, 540, 500);
delay(50);
wave(speakerPin, 300, 400);
delay(1000);
}
This wave() function is all you really need to grasp to play some tones. In
addition to pin number, you can tell it the frequency (A4 is 440 Hz) and
duration in milliseconds.
A short delay between notes makes them sound clearer.
Coding 43
You can treat this wave() function like a black box and just call it. But if
you insist, we’ll show you what’s inside. Period T, the duration of a single
wave (one HIGH + one LOW) is 1/frequency (T=1/f).
This uses the duration that was passed into the function. This code uses
a common idiom to do something for a duration: store the starting time,
check how much time we’ve spent since then, and see if it’s more than
the duration.
You can create a square wave by setting a pin half of the time LOW and
half of the time HIGH. The code that calls the function can specify the
frequency, which is the count of HIGHs and LOWs per second (1Hz = 1/s).
Why not use tone()? The Arduino IDE ships with tone() and noTone(). We
had minor timing problems with tone(). Though our wave() is definitely not
perfect either, it’s very short and is simpler than tone(). This makes prob-
lems much easier to debug. Also, wave() helps you understand how a piezo
speaker actually works.
void setup()
{
pinMode(potPin, INPUT); //
digitalWrite(potPin, HIGH); // internal pullup //
Serial.begin(9600); // bit/s //
}
void loop()
{
int n=analogRead(potPin); //
Serial.println(n); //
delay(400); //
}
analogRead() only works with analog pins (A0, A1…). The pin name has
the letter A in it; e.g., analogRead(A0).
Many examples (including Examples→Analog→AnalogInput) don’t set
pinMode(). But you should. For example, setting the internal pullup on the
next line is only guaranteed to work when the pins are in INPUT mode.
Set the internal pullup resistor for the pin. This connects the pin to +5V
through a large 20 kOhm resistor. When the pin is not connected to
ground, it goes to +5V. This is absolutely required, and enabling it in code
saves you from having to physically add a resistor to your circuit.
Open the serial port. We had some trouble with the serial monitor, so we
used a slower speed than the maximum 115,200 bits per second.
Coding 45
Figure 2-26. Circuit diagram for hellopot.pde
Code Structure
This code uses only one global variable, speed. For fake inertia to work, we
need to know the last speed the robot was moving at as we slow down. This
global variable is used only in loop() to keep the program structure clean.
The speed variable is sent to functions as a regular parameter.
Coding 47
The three input sensors are processed with lineDetected(), getAtten
tion(), and getThreshold().
Outputs include servos, LEDs, and speakers. The most important output
functions are forward(), turn(), sayReady(), and setBlueToRed(). The rest
of the output functions are just helper functions to outputs: pulseServo(),
wave(), and setColor().
// allbutmind.pde - a mind controlled robot without mind control
// (c) Tero Karvinen & Kimmo Karvinen http://MindControl.BotBook.com
float speed=0.0; //
void setup()
{
pinMode(linePin, INPUT);
pinMode(servoLeftPin, OUTPUT);
pinMode(servoRightPin, OUTPUT);
pinMode(potPin, INPUT);
digitalWrite(potPin, HIGH); // internal pullup
pinMode(speakerPin, OUTPUT);
sayReady(); //
}
void loop()
{
while (lineDetected()) turn();
float at=getAttention(); //
float tr=getThreshold(); //
speed=fakeInertia(speed, at, tr); //
forward(speed);
}
bool lineDetected()
{
return ! digitalRead(linePin);
}
float getAttention()
{
return 0.5; // dummy value for testing //
}
float getThreshold()
{
int x=analogRead(potPin); //
float tr=(x-potMin)/potMax; //
setBlueToRed(tr);
return tr;
}
void turn()
{
for (int i = 0; i < 30; i++) {
pulseServo(servoLeftPin, 1500+500);
pulseServo(servoRightPin, 1500+500);
}
}
Coding 49
}
void sayReady()
{
wave(speakerPin, 440, 40);
delay(25);
wave(speakerPin, 300, 20);
wave(speakerPin, 540, 40);
delay(25);
wave(speakerPin, 440, 20);
wave(speakerPin, 640, 40);
delay(25);
wave(speakerPin, 540, 40);
delay(25);
}
This line and the next specify limits of the potentiometer you measured
earlier with hellopot.pde. We’ve shortened the range a bit, so that the user
can easily reach the minimum and maximum value. Even though 14 and
236 could be represented as integers, they must be specified as float
here. That’s because we use the numbers in division, and we want the
results to be floating points. With integers, 1/2=0. But usually, we really
want a float, such as 1.0/2.0=0.5.
Coding 51
Figure 2-28. Hacking the dongle: remove the cover; destroy the connection
marked with green circle; confirm you’ve broken the connection with
multimeter; solder wires to dongle
Start by removing the dongle cover by lifting it from the seam with a screw-
driver.
Use a razor knife to destroy the marked connections. The point of doing this
is to disconnect the dongle USB port to enable you to read data from the RX
and TX pins.
Coding 53
The dongle also needs power. Connect the red positive wire to Arduino’s 3.3
volt output (“3V3”).
Connect the dongle’s TX directly to Arduino’s RX (pin 0). When dongle TX
(transmission) is sending the bit 0 (LOW), the voltage is 0V, same as Arduino
LOW.
What about when the dongle’s TX sends bit 1 to Arduino RX? Surprisingly,
no resistors are needed here. When dongle TX is sending the bit 1 (HIGH),
the voltage is 3.3V. This is one-third less than Arduino’s 5V HIGH. But it’s
still over half of 5V! As 3.3V is more than 2.5V (Arduino’s threshold), Arduino
considers this HIGH. Because the voltage is lower than expected, nothing
will get too hot.
Voltage Divider
Arduino’s TX sending 5V to a dongle pin made for 3.3V requires more tricks.
Connect Arduino TX (pin 1) with a 1.8 kOhm resistor to Dongle TX. Connect
Dongle TX to GND with a 3.3 kOhm resistor.
Arduino sending bit 0 (LOW) is the simpler case. In the top of Figure 2-30,
you can see dongle TX connected to 0V through both resistors. Obviously,
it ends up in ground level, 0V.
What about Arduino sending bit 1, HIGH? Here, the two resistors act as a
voltage divider.
On the top, there is +5V. Then there are two resistors, and finally 0V. Between
the two resistors, dongle RX measures voltage. According to Ohm’s law
(U=IR), the voltage gradually reduces to 0V as you follow the resistors.
The total resistance is 1.8 kOhm + 3.3 kOhm = 5 kOhm. If you start from +5V
and measure the voltage at 1.8 kOhm, the voltage is reduced by 36% (1.8
kOhm / 5 kOhm).
Hello Attention!
Connect your hacked dongle to Arduino. Connect the wires using the bread-
board in your bot (Figure 2-31) according to the circuit diagram (Fig-
ure 2-32).
Coding 55
Figure 2-32. Circuit diagram for helloattention.pde
/* Disconnect TX and RX jump wires from Arduino when uploading from IDE.
Turn robot on, then in a couple of seconds turn headband on. */
void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(tinyLedPin, OUTPUT);
pinMode(speakerPin, OUTPUT);
Serial.begin(115200); // bit/s //
connectHeadset(); //
}
void loop()
{
float att = getAttention(); //
if (att > 0) //
setBlueToRed(att);
toggleTinyLed(); //
}
void connectHeadset()
{
setGreen();
delay(3000);
Serial.write(0xc2); //
setWhite();
}
byte readOneByte()
{
while (!Serial.available()) { //
delay(5); // ms
};
return Serial.read();
}
float getAttention()
{ // return attention percent (0.0 to 1.0)
// negative (-1, -2...) for error
byte generatedChecksum = 0; //
byte checksum = 0;
int payloadLength = 0;
byte payloadData[64] = {
0
Coding 57
};
int poorQuality = 0;
float attention = 0;
/* Sync */
if (170 != readOneByte()) return -1; //
if (170 != readOneByte()) return -1;
/* Length */
payloadLength = readOneByte();
if (payloadLength > 169) return -2; //
/* Checksum */
generatedChecksum = 0;
for (int i = 0; i < payloadLength; i++) { //
// Read payload into array:
payloadData[i] = readOneByte();
generatedChecksum += payloadData[i];
}
generatedChecksum = 255 - generatedChecksum;
checksum = readOneByte();
if (checksum != generatedChecksum) return -3; //
/* Payload */
for (int i = 0; i < payloadLength; i++) { //
switch (payloadData[i]) {
case 0xD0:
sayHeadsetConnected();
break;
case 4: //
i++; //
attention = payloadData[i]; //
break;
case 2:
i++;
poorQuality = payloadData[i];
if (200 == poorQuality) {
setYellow(); //
return -4;
}
break;
case 0xD1: // Headset Not Found
case 0xD2: // Headset Disconnected
case 0xD3: // Request Denied
case -70:
wave(speakerPin, 900, 500);
setWhite();
return -5;
break;
void setGreen()
{
setColor(0, 255, 0);
}
void setYellow()
{
setColor(255, 255, 0);
}
void setWhite()
{
setColor(100, 100, 100);
}
void sayHeadsetConnected()
{
wave(speakerPin, 440, 40);
delay(25);
wave(speakerPin, 300, 20);
wave(speakerPin, 540, 40);
delay(25);
wave(speakerPin, 440, 20);
wave(speakerPin, 640, 40);
delay(25);
wave(speakerPin, 540, 40);
delay(25);
}
Coding 59
{
analogWrite(redPin, 255 - red);
analogWrite(greenPin, 255 - green);
analogWrite(bluePin, 255 - blue);
}
void toggleTinyLed()
{
tinyLedState = !tinyLedState;
digitalWrite(tinyLedPin, tinyLedState);
}
Communication with the dongle is very fast, 115.2 kbit/s. It’s always a
good idea to specify the units in your comments.
At very beginning, we set the main LED to green to ask the user to turn
on the headset.
getAttention() is the heart of the program. It returns attention as a per-
centage, from 0.0 (0%) to 1.0 (100%).
We only show attention with the main LED if there is some. Otherwise, we
leave the main LED set to whatever color it is currently set to: green, white,
or yellow. Function getAttention() could have set it to one of the
following: green (turn on headband), white (no headband-dongle-arduino
connection), or yellow (no EEG, even though headband-dongle-arduino
connection works).
We blink Arduino’s surface mounted LED (pin 13) on every iteration of
loop() to confirm that we’re still running. Normally, the blinking is so fast
it looks like flicker or almost as though the LED was continuously on.
0xc2 is instruction for the dongle to try connecting to any headband it can
find. This has to happen briefly after the headband is turned on, because
the headband is trying to get a connection, too.
Wait until a byte comes from serial. If this means forever, then so be it.
But readOneByte() is guaranteed to return a byte. As a loop with no delay
Coding 61
As of Arduino 1.0, which was still in testing at the
time of this writing, the behavior of flush() is
changing significantly. If you are using Arduino 1.0,
check the book’s catalog page (see “How to Con-
tact Us” on page xiv) for new example code, or visit
the authors’ site at http://botbook.com.
NeuroSky Protocol
How do you begin when faced with an unknown protocol? We did some Goo-
gling, and found that the NeuroSky reference documentation and more was
available on the NeuroSky website. For example, see “MindWave and Ardu-
ino” (NeuroSky 2011), “MindSet Communications Protocol” (NeuroSky
2010), and “arduino_tutorial” in the NeuroSky wiki (http://developer.neuro
sky.com/docs/doku.php?id=start).
The NeuroSky dongle communicates over the serial port. We have wires
going to Arduino RX and TX.
Every packet is of this format: sync (170 170), payload length, payload, and
a checksum (see Table 2-1).
Coding 63
Build the final circuit (Figure 2-33) and upload mindcontrol.pde.
void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(tinyLedPin, OUTPUT);
pinMode(speakerPin, OUTPUT);
pinMode(servoRightPin, OUTPUT);
pinMode(servoLeftPin, OUTPUT);
pinMode(linePin, INPUT);
pinMode(potPin, INPUT);
digitalWrite(potPin, HIGH); // internal pullup
Serial.begin(115200); // bit/s
connectHeadset();
}
void loop()
{
while (lineDetected()) turn();
updateAttention(); //
tr = getThreshold(); //
if (attention > 0)
setBlueToRed(attention);
if (attention > tr) {
speed = attention; //
} else {
speed = speed * 0.98; //
}
forward(speed); //
toggleTinyLed();
}
float getThreshold()
{
int x = analogRead(potPin);
return (x - potMin) / potMax;
}
bool lineDetected()
{
Coding 65
return !digitalRead(linePin);
}
void connectHeadset()
{
setGreen();
delay(3000);
Serial.write(0xc2);
attention = 0;
setWhite();
}
byte ReadOneByte()
{
while (!Serial.available()) { }
return Serial.read();
}
float updateAttention()
{
byte generatedChecksum = 0;
byte checksum = 0;
int payloadLength = 0;
byte payloadData[64] = { 0 };
int poorQuality = 0;
}
if (170 != ReadOneByte()) return -1; //
/* Length */
payloadLength = ReadOneByte();
if (payloadLength > 169)
return -2;
/* Checksum */
generatedChecksum = 0;
for (int i = 0; i < payloadLength; i++) {
payloadData[i] = ReadOneByte(); // Read payload into array
generatedChecksum += payloadData[i];
}
generatedChecksum = 255 - generatedChecksum;
checksum = ReadOneByte();
if (checksum != generatedChecksum) {
return -3;
}
void smartFlush()
{
if (128 / 2 < Serial.available()) { // buffer is 128 B //
Serial.flush();
}
}
Coding 67
for (int i = 0; i < 2; i++) {
pulseServo(servoLeftPin, 1500 + 500 * speed);
pulseServo(servoRightPin, 1500 - 500 * speed);
}
}
void turn()
{
for (int i = 0; i < 20; i++) {
pulseServo(servoLeftPin, 1500 + 500);
pulseServo(servoRightPin, 1500 + 500);
}
}
void setGreen()
{
setColor(0, 255, 0);
}
void setYellow()
{
setColor(255, 255, 0);
}
void setWhite()
{
setColor(100, 100, 100);
}
void toggleTinyLed()
{
tinyLedState = !tinyLedState;
digitalWrite(tinyLedPin, tinyLedState);
}
void sayHeadsetConnected()
{
wave(speakerPin, 440, 40);
delay(25);
wave(speakerPin, 300, 20);
wave(speakerPin, 540, 40);
delay(25);
wave(speakerPin, 440, 20);
wave(speakerPin, 640, 40);
delay(25);
wave(speakerPin, 540, 40);
delay(25);
}
Coding 69
Moving forward uses a floating point percentage (0.0 to 1.0), the same
range as attention and threshold. There is no hurry returning from for-
ward, because we call updateAttention() from pulseServo(), the low-
level command called by forward().
Skip until we get to the beginning of NeuroSky packet, marked by sync
sequence start 170. The function smartFlush() only flushes the buffer if
it’s near overflow.
The second byte of sync sequence 170 170.
Update global variable attention. This is the main purpose of updateAtten
tion().
The buffer is 128 bytes. We can’t let it overflow, as that seems to crash
the bot. But we want to catch up to whatever messages came while we
were busy moving servos. So we only flush (delete the contents of) the
buffer if it’s half full. The 50% fill value was found by experimentation.
We can move servos for two minutes if we want to. This is very useful if
you want to add preprogrammed sequences, such as long turns or more
obstacle avoidance. The attention value will be updated and the serial
buffer kept away from overflow. Feel free to put updateAttention() in any
of your own functions.
Congratulations! You’ve now finished your mind-controlled robot!
This is not the end, this is the beginning. What’s the next mind-controlled
project in your mind?
See you at http://BotBook.com!
Coding 71
A/Building the
ScrewShield
Start by putting two 8-pin headers (see Figure A-1) into the pin holes of the
“digital” wing (the one with RX and TX pins). Use some poster putty such as
Blu-Tack to hold pins in place (Figure A-2). Otherwise they will easily get
misaligned when you are soldering them from the other side.
Mount the wing to third-hand tool or similar (Figure A-3). You can’t hold it
yourself while you are soldering, as you need one hand for soldering iron and
other for the solder. Turn the wing upside down and solder the pins in place.
73
Figure A-2. Poster putty holds two 8-pin headers in place
Figure A-5. Forming two 6-pin blocks and two 8-pin blocks
Now use poster putty to put the terminal blocks in place. 6-pins blocks go to
the “analog” wing and 8-pins blocks to the “digital” wing (Figure A-6).