Baixe Programming Lego Robots using NBC e outras Notas de estudo em PDF para Análise de Sistemas de Engenharia, somente na Docsity!
Programming Lego Robots
using NBC
(Version 1.0, June 11, 2007)
(Requires NBC 1.0.1.b30 or greater)
by Ross Crawford
with revisions by John Hansen
Preface
The Lego MindStorms NXT robot is a wonderful new toy from which a wide variety of robots can be
constructed, that can be programmed to do all sorts of complicated tasks. Unfortunately, the software that comes
with the robot, although visually attractive and much more powerful than the RIS software for the RCX, is still
somewhat limited in its functionality. To unleash the full power of your robot, you need a different programming
environment. NBC is a programming language, written by John Hansen, which is especially designed for the
Lego robots. If you have never written a program before, don't worry. NBC is really easy to use and this tutorial
will tell you all about it. Actually, programming robots in NBC is a lot easier than programming a normal
computer, so this is a chance to become a programmer in an easy way.
To make writing programs even easier, there is the Bricx Command Center. This utility helps you to write your
programs, to send them to the robot, and to start and stop the robot. Bricx Command Center works almost like a
text processor, but with some extras. This tutorial will use Bricx Command Center (version 3.3.7.15 or higher) as
programming environment. You can download it for free from the web at the address
http://bricxcc.sourceforge.net/
Bricx Command Center runs on Windows PC’s (95, 98, ME, NT, 2K, XP). The language NBC can also be
downloaded from the web at address
http://bricxcc.sourceforge.net/nbc/
Acknowledgements
I would like to thank John Hansen for developing NBC. Also many thanks to Mark Overmars for writing his
NQC tutorial, on which this is heavily based.
- Preface ___________________________________________________________________
- Acknowledgements ____________________________________________________________________
- Contents __________________________________________________________________
- I. Writing your first program __________________________________________________
- Building a robot ______________________________________________________________________
- Starting Bricx Command Center __________________________________________________________
- Writing the program ___________________________________________________________________
- Running the program __________________________________________________________________
- Errors in your program _________________________________________________________________
- Changing the speed ____________________________________________________________________
- Adding comments _____________________________________________________________________
- Summary ___________________________________________________________________________
- II. Using variables _________________________________________________________
- Moving in different ways ______________________________________________________________
- Displaying results on the screen _________________________________________________________
- Random numbers ____________________________________________________________________
- Summary ___________________________________________________________________________
- III. Flow Control __________________________________________________________
- The cmp and tst statements _____________________________________________________________
- The brcmp and brtst statements__________________________________________________________
- The jmp statement____________________________________________________________________
- Loops – repeating code ________________________________________________________________
- Summary ___________________________________________________________________________
- IV. Sensors _______________________________________________________________
- Waiting for a sensor __________________________________________________________________
- Acting on a touch sensor _______________________________________________________________
- Light sensors ________________________________________________________________________
- Summary ___________________________________________________________________________
- V. Making music___________________________________________________________
- Playing tones ________________________________________________________________________
- Playing files ________________________________________________________________________
- Creating your own sound files __________________________________________________________
- Summary ___________________________________________________________________________
- VI. Threads and subroutines _________________________________________________
- Threads ____________________________________________________________________________
- Subroutines _________________________________________________________________________
- Defining macros _____________________________________________________________________
- Summary ___________________________________________________________________________
- VII. More about motors _____________________________________________________
- Stopping gently ______________________________________________________________________
- Synchronising motors _________________________________________________________________
- Regulating the motor speed_____________________________________________________________
- Rotating a specific angle _______________________________________________________________
- More advanced motor control ___________________________________________________________
- Summary ___________________________________________________________________________
- VIII. More about sensors ____________________________________________________
- Sensor type _________________________________________________________________________
- Sensor mode ________________________________________________________________________
- Sound sensor ________________________________________________________________________
- Motor as a rotation sensor ______________________________________________________________
- Ultrasonic sensor_____________________________________________________________________
- More advanced sensor control __________________________________________________________
- Putting it all together__________________________________________________________________
- Summary ___________________________________________________________________________
- IX. Parallel threads ________________________________________________________
- A wrong program ____________________________________________________________________
- Using mutexes_______________________________________________________________________
- Summary ___________________________________________________________________________
- X. Communication between robots ____________________________________________
- Communication with other NXT bricks ___________________________________________________
- Communication with a PC _____________________________________________________________
- Communication with other Bluetooth devices ______________________________________________
- Summary ___________________________________________________________________________
- XI. More commands ________________________________________________________
- System calls ________________________________________________________________________
- System clock ________________________________________________________________________
- Arrays _____________________________________________________________________________
- Type declarations ____________________________________________________________________
- Type aliases_________________________________________________________________________
- Summary ___________________________________________________________________________
I. Writing your first program
In this chapter I will show you how to write an extremely simple program. We are going to program a robot to
move forwards for 4 seconds, then backwards for another 4 seconds, and then stop. Not very spectacular but it
will introduce you to the basic idea of programming. And it will show you how easy this is. But before we can
write a program, we first need a robot.
Building a robot
The robot we will use throughout this tutorial is the “Tribot”, the instructions for which are included with your
NXT set. If you are new to LEGO robotics, I recommend doing the tutorials that come with the LEGO software,
to get acquainted with what your NXT can do. Your robot should look like this:
(Note that you may already have added sensors and a grabber – if so, you should remove them temporarily, as
some of the examples may not work correctly with them attached.)
Starting Bricx Command Center
We write our programs using Bricx Command Center. Start it by double clicking on the icon BricxCC. (I assume
you already installed Bricx Command Center. If not, download it from the web site (see the preface), and install
it in any directory you like.) The program will ask you where to locate the robot. Switch the robot on and press
OK. The program will (most likely) automatically find the robot. Now the user interface appears as shown below
(without a window).
This statement tells the robot to start output B, that is, the motor connected to the output labeled B on the NXT,
to move forwards. The 100 specifies the percentage of maximum speed, so it will move with maximum speed.
OnFwd(OUT_C,100)
Same statement but now we start motor C. After these two statements, both motors are running, and the robot
moves forwards.
wait 4000
Now it is time to wait for a while. This statement tells us to wait for 4 seconds. The argument gives the number
of milliseconds, or 1/1000 of a second. So you can very precisely tell the program how long to wait. So for 4
seconds, the program does nothing and the robot continues to move forwards.
OnRev(OUT_BC,100)
The robot has now moved far enough so we tell it to move in reverse direction, that is, backwards. Note that we
can set both motors at once using OUT_BC as argument. We could also have combined the first two statements
this way. We could also use OnFwd(OUT_BC,-100).
wait 4000
Again we wait for 4 seconds.
Off(OUT_BC)
And finally we switch both motors off.
exit
This statement tells the NXT this thread has finished. While not required at the end of threads, it is
recommended. Note also that it can appear elsewhere in the thread as well.
That is the whole program. It moves both motors forwards for 4 seconds, then backwards for 4 seconds, and
finally switches them off.
You probably noticed the colors when typing in the program. They appear automatically. The colors and styles
used by the editor when it performs syntax highlighting are customizable.
Running the program
Once you have written a program, it needs to be compiled (that is, changed into code that the robot can
understand and execute) and sent to the robot using either the USB cable or a Bluetooth device (called
“downloading” the program). Before you can do that, you need to name the program, which you do by saving it
to your hard drive. When you save it, make sure the file extension is “.nbc”, this tells Bricx Command Center
that it is an NBC program.
Once it has been saved, you can compile and download it simply by clicking the download button. Assuming
you made no errors when typing in the program, it will correctly compile and be downloaded. (If there are errors
in your program you will be notified; see below.)
Now you can run your program. To do this, go to “Software Files” on your NXT, and look for “1-simple”, then
use the orange NXT button to run it. Or alternatively, you can run it from Bricx Command Center, by pressing
the green run button on your window (see the figure above). Does the robot do what you expected? If not, the
wires are probably connected incorrectly.
Errors in your program
When typing in programs there is a reasonable chance that you make some errors. The compiler notices the
errors and reports them to you at the bottom of the window, like in the following figure:
It automatically selects the first error (we mistyped the name of the motor). When there are more errors, you can
click on the error messages to go to them. Note that often errors at the beginning of the program cause other
errors at other places. So better only correct the first few errors and then compile the program again.
/* Forward and reverse
by Ross Crawford
This program makes the robot go forward and backward */
#define SPEED 25 #define MOVE_TIME 4000
thread main OnFwd(OUT_BC, SPEED) // Drive forward wait MOVE_TIME // Wait for 4 seconds OnRev(OUT_BC, SPEED) // Drive backward wait MOVE_TIME // Wait for 4 seconds Off(OUT_BC) // Stop moving exit // Exit endt
Summary
In this chapter you wrote your first program in NBC, using Bricx Command Center. You should now know how
to type in a program, how to download it to the robot and how to let the robot execute the program. Bricx
Command Center can do many more things. To find out about them, read the documentation that comes with it.
This tutorial will primarily deal with the language NBC and only mention features of Bricx Command Center
when you really need them.
You also learned some important aspects of the language NBC. First of all, you learned that each program has
one thread named main that is always executed by the robot. Also you learned the four most important motor
commands: OnFwd, OnRev and Off, and about the wait and exit statement. Finally, you learned about how to
use constants to make program-wide changes easier, and comments to explain what your code does.
II. Using variables
Variables form a very important aspect of every programming language. Variables are memory locations in
which we can store a value. We can use that value at different places and we can change it. Let me describe the
use of variables using an example.
Moving in different ways
Assume we want to adapt the above program in such a way that the robot doesn’t return as fast as it went
forward. This can be achieved by making the speed value smaller for the return journey. But how can we do
this? SPEED is a constant and constants cannot be changed. We need a variable instead. Variables can easily be
defined in NBC. Here is a new program.
#define MOVE_TIME 4000 #define SPEED 100 #define DECREMENT 25
dseg segment Speed byte dseg ends
thread main set Speed SPEED OnFwd(OUT_BC, Speed) wait MOVE_TIME sub Speed, Speed, DECREMENT OnRev(OUT_BC, Speed) wait MOVE_TIME Off(OUT_BC) exit endt
We have introduced the variable Speed into the program. Every variable in your program must be declared in a
data segment. You can have as many data segments as you want, and they can be pretty much anywhere in your
program. All variables in NBC have global scope – they are accessible from any code in any thread.
Data segments start with the segment statement, and end with the ends statement. Each segment must be
named, the name on the segment and ends statements must match.
So let's explain the new statements in this program.
dseg segment
This statement specifies the start of a data segment called “dseg”. In our program, it is the only data segment and
contains only a single variable.
Speed byte
This statement declares the variable “Speed” as type “byte”. Variable names must start with a letter but can
contain digits and the underscore sign. No other symbols are allowed. (The same applied to constants, thread
names, etc.)
dseg ends
This statement specifies the end of the “dseg” data segment.
set Speed, SPEED
This statement assigns the value of SPEED (the constant defined earlier) to the variable Speed. Note that this can
also be done in the declaration of the variable, by adding the initial value after the variable type, eg: Speed
byte SPEED.
sub Speed, Speed, DECREMENT
This subtracts the value DECREMENT from the value currently stored in the variable Speed, and stores the
result back to that same variable.
Displaying results on the screen
As you can see, if perform these commands, the final value of ccc should be 15. But how do we check it? The
easiest way is to display the result on the NXT screen. This is fairly simple – there is a system call available to
do it. The following program demonstrates it:
dseg segment aaa byte bbb byte ccc byte dseg ends
thread main set aaa, 10 // aaa is now equal to 10 mul bbb, 20, 5 // bbb is now equal to 100 mov ccc, bbb // ccc is now equal to 100 div ccc, ccc, aaa // ccc is now equal to 10 add ccc, ccc, 5 // ccc is now equal to 15
NumOut(10, LCD_LINE7, ccc) wait 2000 // wait so you get to see it!
exit endt
This is fairly self-explanatory, but here is an explanation of the important parts.
NumOut(10, LCD_LINE7, ccc)
This statement converts the value ccc to a string, then calls the system function DrawText to display the string
on the screen. The value of ccc should be displayed near the lower left of the screen.
wait 2000
We’ve seen this before too – it is here simply to pause and allow you to see the result. If it wasn’t here, the
program would exit immediately, and the NXT menu would overwrite the value you just displayed too fast for
you to see it!
Random numbers
In all the above programs we defined exactly what the robot was supposed to do. But things get a lot more
interesting when the robot is going to do things that we don’t know. We want some randomness in the motions.
In NBC you can create random numbers. The following program uses this to pick a random speed when it
reverses.
#define MOVE_TIME 4000 #define SPEED 100 #define DECREMENT 25
dseg segment Speed byte wRandom byte dseg ends
thread main set Speed SPEED OnFwd(OUT_BC, Speed) wait MOVE_TIME Random(wRandom,30) add wRandom, wRandom, 10 sub Speed, Speed, wRandom OnRev(OUT_BC, Speed) wait MOVE_TIME Off(OUT_BC) exit endt
The program is basically the same as the one above, but instead of just subtracting 25 from Speed, it uses a
random number between 10 and 40. Let’s look at how it does this:
Random(wRandom,30)
This statement generates a random integer between 0 and 29 (inclusive), and returns the result in wRandom.
Note that the result will always be less then the value of the 2
nd
parameter.
add wRandom, wRandom, 10
This statement adds 10 to the result, so it will now be between 10 and 39.
sub Speed, Speed, wRandom
This statement subtracts the result from the current value of Speed, ready to change the random speed in the
following OnRev statement.
Summary
In this chapter you learned about the use of variables. Variables are very useful, but they are restricted to only
integer values. But for many robot tasks this is good enough.
You also learned how to display a value on the NXT screen. This technique can be very useful for debugging
more complex programs.
Finally, you learned how to create random numbers, such that you can give the robot unpredictable behavior.
The brcmp and brtst statements
So, we can store the result of a comparison for later using cmp or tst. And we can display it on the screen. But
how can we actually use it to do something? Generally, a robot will want to do something different depending on
the result of the test, and this can be accomplished with brcmp and brtst.
In NBC, all program branch statements require a label. The label is just a string of characters followed by a
colon. A label can be on a line by itself or at the start of a line containing an NBC statement. Let’s have a look
at an example:
dseg segment aaa byte bbb byte wRandom byte dseg ends
thread main set aaa, 10 Random(wRandom,20) mov bbb, wRandom
NumOut(10, 8, bbb)
brcmp GT, Bigger, bbb, aaa TextOut(50, 8, 'small') brcmp LTEQ, Delay, bbb, aaa Bigger: TextOut(50, 8, 'BIG') Delay: wait 2000
exit endt
Again, this is fairly similar to the last program, but instead of using cmp to store the comparison result, we use
brcmp to execute some “conditional” code. Let’s analyse the 2 new statements:
brcmp GT, Bigger, bbb, aaa
This looks very similar to the cmp statement in the last program doesn’t it? In fact it is, and the exact same
comparison is performed, but instead of storing the result, it is used to determine whether or not to skip program
execution to the label “Bigger”, which is defined below. If the comparison is true, the program skips, otherwise
it continues with the next statement, which displays the string “small”.
Bigger:
This is a label, and is the target of the brcmp statement. If the comparison is true, program execution will skip
to the first statement following this label, which displays the string “BIG”.
So the program will display the value of bbb, and either “BIG” or “small” depending whether or not it’s bigger
than aaa.
The brtst statement is, again, similar to brcmp, except that the 4 th^ parameter is assumed to be zero.
The jmp statement
Sometimes you need to do an unconditional branch, that is, skip some code no matter what. This can be
accomplished with the jmp statement. It is very simple; you just specify the label you want to skip to.
One common use of unconditional branches is in an “if-then-else” type of situation. You use brcmp or brtst as
the “if”, jumping to a label to execute the “then” code. If the comparison is false, you execute the “else” code,
immediately below the conditional branch. But at the end of that code, you want to skip over the “then” code,
because you don’t want to execute that if the test is false. So you must add a label after the “then” code, and skip
to it unconditionally at the end of the “else” code. Let’s look at an example:
#define MOVE_TIME 4000 #define SPEED 100 #define DECREMENT 25
dseg segment Speed byte wRandom byte dseg ends
thread main set Speed SPEED OnFwd(OUT_BC, Speed) wait MOVE_TIME sub Speed, Speed, DECREMENT Random(wRandom,2) brtst EQ, Then, wRandom Else: OnRev(OUT_BC, Speed) jmp EndIf Then: OnFwd(OUT_BC, Speed) EndIf: wait MOVE_TIME Off(OUT_BC) exit endt
Here is an example “if-then-else”. In this example, our robot should go forward at full speed for 4 seconds, then
go either forwards or reverse at slower speed for another 4 seconds, depending on a random number. Let’s
analyze it:
brtst EQ, Then, wRandom
This is the conditional branch, or “if” statement. If wRandom is equal to zero, program execution will skip to the
“Then” label.
Else:
This is a label identifying the “Else” clause, that is the code which is executed if the comparison is false. Note
that this label is in fact unnecessary, as no branch statement uses it as a target. It was included to highlight the
similarity to an if-then-else construct, and also to demonstrate that it is OK to put labels in your code which are
not the target of branch statements. So if the test is false, the OnRev statement will be executed, and the robot
will back up.
jmp EndIf
This unconditional branch causes program execution to skip to “Endif”, thus avoiding execution of the “Then”
clause.
Then:
The “Then” label is the target of the brtst statement above, so if the test is true, program execution will skip to
this point, thus missing the “Else” clause, and the robot will continue forwards, due to the OnFwd statement.
EndIf:
The “Endif” label is the target of the unconditional branch at the end of the “Else” clause.
If you run this program a few times, your robot should go forward about half the time and backward about half
the time.
Loops – repeating code
You can make your robot turn by stopping or reversing the direction of one of the two motors. Here is an
example. Type it in, save it, download it to your robot and let it run. It should drive a bit and then make a 90-
degree right turn.
#define MOVE_TIME 800 #define TURN_TIME 200
dseg segment SquareCount byte 4 RepeatCount byte 10 dseg ends
thread main
RepeatLoop: set SquareCount, 4
SquareLoop: OnFwd(OUT_BC,100) wait MOVE_TIME OnRev(OUT_C,100) wait TURN_TIME sub SquareCount, SquareCount, 1 brtst GT, SquareLoop, SquareCount
sub RepeatCount, RepeatCount, 1 brtst GT, RepeatLoop, RepeatCount
Off(OUT_BC) endt
There is now one loop inside the other. We call these “nested” loops. You can nest loops as much as you like.
Notice that each loop is indented – this is not necessary, but helps to make the program easier to read. Note also
that although SquareCount is initialized in the variable declaration, it needs to be reset to 4 before each time
through the SquareLoop. This is necessary because the previous execution of that loop leaves the value at
zero.
Summary
In this chapter you learned about how to compare values in your program and store the result, using the tst and
cmp statements. You learned how to conditionally skip code using labels and the brtst and brcmp statements,
and unconditionally skip code using the jmp statement. Finally, you learned how to use the brtst, brcmp and
jmp statements to write if-then-else clauses and loops.
IV. Sensors
One of the nice aspects of the Lego robots is that you can connect sensors to them and that you can make the
robot react to the sensors. Before I can show how to do this we must change the robot a bit by adding a sensor.
To do this, you will need to follow the instructions in the software that came with your NXT. You need to build
the “bumper” for you tribot, according to those instructions, and your robot should now look like this:
Connect the sensor to input 1 on the NXT.
Waiting for a sensor
Let us start with a very simple program in which the robot drives forwards until it hits something. Here it is:
dseg segment Switch sword 0 dseg ends
thread main SetSensorTouch(IN_1) OnFwd(OUT_BC,100)
CheckSensor: ReadSensor(IN_1,Switch) brtst EQ, CheckSensor, Switch
Off(OUT_BC) endt
Let’s look at the important lines:
SetSensorTouch(IN_1)
This tells the NXT that the sensor connected to the input IN_1 will be a touch sensor.
ReadSensor(IN_1,Switch)
This reads the current value of the sensor, translates it to an appropriate value depending on the sensor type
selected, and returns it in the 2 nd^ parameter. So in our program, Switch will contain either 1 or 0 (true/false) after
this call, depending whether the touch sensor is pressed or not.