PROGRAMMING
FUNDAMENTALS
If you were to watch old movies, you would get the idea that all you needed to build a robot
were a couple of motors, a switch or relay, a battery, and some wire. In actuality, most
robots, including the hobby variety, are equipped with a computational brain of one type or
another that is told what to do through programming. The brain and programming are typically
easier and less expensive to implement than are discrete circuitry, which is one reason
why it's so popular to use a computer to power a robot.
The nature of the programming depends on what the robot does. If the robot is meant
to play tennis, then its programming is designed to help it recognize tennis balls, move in
all lateral directions, perform a classic backhand, and maybe jump over the net when it
wins.
But no matter what the robot is supposed to do all of the robot's actions come down to
a relatively small set of instructions in whatever programming language you are using. If
you're new to programming or haven't practiced it in several years, read through this chapter
on the basics of programming for controlling your robots. This chapter discusses rudimentary
stuff so you can better understand the more technical material in the chapters that
follow.
Even if you are familiar with programming, please take a few minutes and read through
the chapter. Important concepts needed for programming robots are presented along with
some of the fundamental program templates used for programming robots. If you were to
skip this chapter, you may become confused at some of the code examples and programming
discussions presented later in the book.
13.1 Important Programming Concepts
There are eight critical concepts to understanding programming, whether for robots or
otherwise.
In this chapter, well talk about each of the following in greater detail:
- Linear program execution
- Variables and I/O ports
- Assignment statements
- Mathematical expressions
- Arrays and character strings
- Decision structures
- Macros, subroutines, and functions
- Console I/O
13.1.1 LINEAR PROGRAM EXECUTION
Modern computer systems, regardless of their sophistication, are really nothing more than
electronic circuits that read instructions from their memory in order and execute them as
they are received. This may fly in the face of your perception of how a computer program
works; especially when you are familiar with working on a PC in which different dialog
boxes can be brought up at different times and different buttons or controls can be accessed
randomly and not in any predefined sequence. By saying that a computer program is a
sequence of instructions that are read and executed may seem to belittle the amount of
work that goes into them along with the sophistication of the operations they perform, but
this is really all they are.
A sequence of instructions to latch data from a storage location into an external register
using two I/O registers (one for data and one for the register clock line) could be:
In this sequence of instructions, the address each instruction is stored in has been included to
show that each incrementing address holds the next instruction in sequence for the program.
The first computers could only execute the sequence of instructions as-is and not modify
the execution in any way. Modern computers have been given the ability to change which
section of instruction sequence is to be executed, either always or conditionally.
The following sequence of instructions will latch the values of one to five into the external
register by conditionally changing the section of the instruction sequence to be executed,
based on the current value.
In the second program, after the contents of 'Holding Register "A" ' have 1 added to them,
the value has 5 subtracted from it and if the result is not equal to zero, execution continues
at address 6 rather than ending after address 14. Note that data from a "Storage Location"
cannot pass directly to an output port nor can mathematical operations be performed on it
without storing the contents in the "Holding Register" first. In this simple program, you can
see many of the programming concepts listed in operation, and while they will seem unfamiliar
to you, the operation of the program should be reasonably easy to understand.
The sequential execution of different instructions is known as linear program execution and is the basis for program execution in computers. To simplify the creation of instruction
sequences, you will be writing your software in what is known as a high-level language or,
more colloquially, a programming language. The programming language is designed for
you to write your software (or code) in a format similar to the English language, and a computer
program known as a compiler will convert it into the sequence of instructions needed
to carry out the program.
If you were given instruction in programming before reading this book, you may have been
presented with the concept of flowcharts—diagrams that show the flow of the application
code graphically as passing through different boxes that either perform some function or
control the direction the path of execution takes. Fig. 13-1 shows an example flowchart for
a robot program in which a robot will go forward until it encounters an object and then
reverse and turn left for a half second. The advantage of using flowcharts in teaching programming
is how well they describe simple applications graphically and show the operation
of high-level programming concepts in a form that is easy to understand.
Flowcharts have four serious drawbacks that limit their usefulness. First, they do not
work well for low-level programming concepts. A simple arithmetic statement that multiplies
two values together and stores the product in different locations is written as:
A = B × C
In most programming languages this is easily understood by everyone by virtue that this
is a simple equation taught in grade school. The flowcharting standard does not easily handle
this operation.
At the other end of the spectrum, flowcharts cannot easily describe complex programming
concepts like the select statement in PBASIC (described in Chapter 15) or sequences
of operations.
The third issue with flowcharting is that they are hard to change when a new feature
is added to a program or mistakes in the program are corrected. This program is alleviated
somewhat with computer-aided graphical programs, but it is still a chore to update a
flowchart.
Finally, flowcharts do not show what programs are doing very effectively. Computer programming
languages are literally that; a language used by a human to communicate with a
computer that is similar in format as a spoken or written language used to communicate
ideas and concepts to other humans. While programs may seem difficult to read, their function
can usually be determined by applying the same rules of logic used when communicating
with other people. This is not true with flowcharting, where the function of the program
is difficult to find in a moderately complex diagram.
Flowcharts are effective in explaining certain types of programming operations, but
their inability to represent multiple statement types as well as not being very efficient in
describing complex programs with different types of statements has pushed them away
from the forefront of computer programming education. There are some applications
that use a flowcharting format (the programming interface for Lego Mindstorms and National Instruments' LabView are the most popular), but for the most part computer (and
robot) programming is carried out using traditional text-based linear execution programming
languages. The use of these programming languages for robotics is discussed in the
following.
13.1.3 VARIABLES AND I/O PORTS
The term variable comes from the notion that the data is not constant and has to be stored
somewhere for later use. Even if you knew what the data value was at some time, it may have
changed since the last time it was checked; variable data isn't static. To be able to store and
find data in a changeable place is a keystone to programming.
Memory in a computer can be thought of as a series of mailboxes, like the ones shown
in Fig. 13-2. Each variable is given a name or a label to allow a program to access it. When
data is accessed, this name is used by the computer to retrieve or change the value stored
in it. Using the variable names in the mailboxes of Fig. 13-2, an arithmetic assignment statement
can be created:
i = 7
In this statement, the variable i will store the value 7; this is an example of storing a constant
value in a variable. Variables can be read and their value can be stored in another variable
like
j = k
in which the contents of k are stored in j. While the statement is described as storing the
contents of one variable into another, the original (value source) variables contents don't
change or are taken away—the value is copied from k and the same value put into j. At the
end of the statement, both j and k store the same value.
Finally, in
i = (j * k) + Src
the computer will retrieve the contents of j, k and Src, find the product of j and k, add it to
Src, and then save the computed value into i. This is an example of a complex assignment
statement, which will be discussed later in the chapter.
I/O ports and hardware special function registers usually use the variable format for reading
and writing values into the computer's hardware. So, to output 123 from a computer system
I/O port, a statement like this is used:
IOPort = 123
When you are new to programming, this can be confusing. Hardware that is treated like
registers can be difficult to visualize (especially when you retrieve the value of a register and
find that it has changed due to a changing input or a counter value).
The data stored in variables come in many forms, and how you choose to store and display
data can make your programming much easier to work through or much harder due to
many difficult to find errors. There are three different aspects of data, including the amount
of space used to store individual values, the format the data is displayed in, and whether relevant
pieces of data can be stored together. These three aspects are discussed in the following
two sections.
13.1.3.1 Data Types Several different data types are available to all types of programming
for storing data in variables and I/O ports. Which one you choose will depend on the
data being stored in them. The values might represent a number like 1 or 127, the numeric
equivalent of a text character (65 is "A" using the ASCII standard), or a binary value like
00010001, which could mean "run both motors forward" in your robot.
No matter what form the data type is in, most programming languages expect to see
data follow predefined types. This is necessary so the data can be properly stored in
memory. The most common data type is the eight-bit integer, so-called because the value
stores an integer (a whole number) using eight bits. With eight bits, the program can
work with a number from 0 to 255 (or -128 to +127, depending on how it uses the
eighth bit). The basic data types that you can expect in a programming language are as
follows:
- one-bit value, which can hold a 1/0, true/false or high/low value
- eight-bit integer, or byte (can hold a number or a string value)
- eight-bit ASCII character
- 16-bit integer, or word
- 32-bit integer, or long or double word (dword)
- 32-bit floating point, or single (floating point means a number with a decimal point)
In many cases, the language provides for either or both signed and unsigned values. The
first bit (called the most significant bit, or MSB) is either 0 or 1, which means a positive or
negative value. With a 16-bit unsigned integer, for example, the program can store values
from 0 to 65535. With a 16-bit signed integer, the program can store values from -32768
to +32767.
13.1.3.2 Number Bases In school you learned that when every number is written
out, it is done as part of a base or radix. This is the number of different characters a single
digit can have. We are most familiar with the base 10 (known as decimal) due to the number
of fingers we have, allowing our ancestors to easily count and add without the need for
a pencil and paper.
Values larger than the maximum number of characters allowed in a single digit caused
additional, higher value digits to be used. These digits are multiplied by the next power of
the number base. To illustrate what this means, consider the number 123.
The value is larger than what a single digit can be so digits multiplied by different powers
of the base are used.
The single digits are multiplied by the base to the power 0. "Tens" are the base to the
power 1 and "hundreds" are the base to the power 2. The number can be written out mathematically
as:
3 × 10° = 3 × 1 = 3
2 × 101 = 2 × 10 = 20
1 × 102 = 1 × 100 = 100
Total = 123
Decimal is the most convenient base for humans to work with, but it isn't for computers.
Computer circuitry is built from digital logic, which can be either a one (1) or zero (0).
Rather than develop circuitry that only works with base 10 numbers, computer designers
instead have chosen to have them work in terms of base 2, or binary. The operation of
binary is identical to that of decimal, except each digit is a power of 2, not a power of 10.
Using this information, Table 13-1 was developed to show the values for each digit of
an eight-bit binary number. Note that the bit number is actually the power of 2 for the
digit.
TABLE 13-1 Binary number values. The “%” in front of the binary number is
used to indicate the value is binary and not decimal or hexadecimal.
Knowing the decimal values for each bit, a decimal number can be converted to a binary
number by taking away the highest possible value. The decimal number 123 can be converted
to binary as:
So, the binary number 01111011 is equivalent to the decimal number 123. When binary
numbers are written in this book, they are proceeded by a percent (%) character, which is
used in BASIC to indicate that a number is binary and not decimal.
Binary numbers can be cumbersome to work with—it should be obvious that trying to
remember, say, and record "zero-one-one-one-one-zero-one-one" is tedious at best. To help
make working with large binary numbers easier, hexadecimal, or base 16, numbers (which
can be represented by four bits) is commonly used. Hexadecimal numbers consist of the first
10 decimal digits followed by the first six letters of the alphabet (A through F) as shown in
Table 13-2.
TABLE 13-2 Hexadecimal values with binary and decimal equivalents. Note
the “$” in front of the hexadecimal number is used as an indicator like “%”
for binary numbers.
The same methodology is used for converting decimal values to hexadecimal as was used
for binary, except that each digit is 16 times the previous digit. The "123" decimal works out
to $7B where the "$" character is used in BASIC to indicates it's a hexadecimal number.
When programming, it is recommended that binary values are used for single bits, hexadecimal
is used for register values, and decimal for everything else. This will make your program
reasonably easy to read and understand and imply what the data is representing in the
program without the need for explaining it explicitly.
13.1.4 ASSIGNMENT STATEMENTS
To move data between variables in a computer system, you will have to use what is known
as an assignment statement; some value is stored in a specific variable and uses the format
DestinationVariable = SourceValue
where the SourceValue can be an explicit number (known as a constant, literal, or immediate
value) or a variable. If SourceValue is a variable, its contents are copied from SourceValue
and the copy of the value is placed into DestinationVariable. Going back to the previous section,
the SourceValue could also be a structure or union element.
The most correct way of saying this is "The contents of SourceValue are stored in
DestinationValue," but this implies that the number is physically taken from SourceValue
(leaving nothing behind) and storing it in DestinationValue. It has to be remembered that the
value stored in SourceValue does not change in an assignment statement
13.1.4.1 Mathematical Expressions A computer wouldn't be very useful if all it
could do is load variables with constants or the value of other variables. They must also be able to perform some kind of arithmetic manipulation on the values (or data) before
storing them into another variable (or even back into the same variable). To do this, a number
of different mathematical operations are available in all high-level programming languages
to allow you to modify the assignment statement with mathematical functions in
the format
DestinationVariable = SourceValue1 + SourceValue2
in which DestinationVariable is loaded with the sum of SourceValue1 and SourceValue2.
DestinationVariable must be a variable, but SourceValue1 and SourceValue2 can be either
constants or variables. Their values are read by the computer, stored in a temporary area
within the processor, added together, and the result (sum) is stored into the destination
variable.
Along with being able to add two values together, programming languages provide a
number of different mathematical (addition, subtraction, multiplication, and division) operations
that can be performed on variables as well as bitwise (AND, OR, XOR) and comparison (equals, less than, greater than, etc.). Table 13-3 lists the commonly used mathematical
operations in computer programming.
The characters used to represent the different operations may have some differences
between languages, but for the most part they are quite consistent for the basic mathematical
operations. Multiple operations can be performed from a single expression, resulting in
a very complex mathematical process being carried out within the computer from a string
of characters that were quite easy for you to input into the computer program.
13.1.4.2 Order of Operations All but the oldest or very simple programming languages
can handle more than one operator in an expression. This allows you to combine
three or more numbers, strings, or variables together to make complex expressions, such as
5 + 10 / 2 * 7
This feature of multiple operators comes with a penalty, however. You must be careful
of the order of precedence or operation, that is, the order in which the program evaluates
an expression. Some languages evaluate expressions using a strict left-to-right process (the
Parallax BASIC Stamp 2 PBASIC language is one), while others follow a specified pattern
where certain operators are dealt with first, then others. This is known as the order of operations and ensures that the higher priority operations execute first. The common order of
operations for most programming languages is listed in Table 13-3.
TABLE 13-3 Different Mathematical Operators and Their Order of Operations
or Priority
The programming language usually does not distinguish between operators that are on
the same level or precedence. If it encounters a _ for addition and a - for subtraction, it will
evaluate the expression by using the first operator it encounters, going from left to right.
You can often specify another calculation order by using parentheses. Values and operators
inside the parentheses are evaluated first.
Keeping the order of operations straight for a specific programming language can be difficult,
but there is a way of forcing your expressions to execute in a specific order and that is to place parentheses around the most important parts of the expression. For example, if
you wanted to find the product of 4 and the sum of 5 and 3 and store it in a variable, you
could write it as
A = 4 * (5 + 3)
in your program to ensure that the sum of 5 and 3 is found before it is multiplied by 4. If the
parentheses were not in place, you would probably have to use a temporary variable to save
the sum before calculating the product, like
temp = 5 + 3
A = 4 * temp
to ensure the calculation would be performed correctly.
13.1.4.3 Using Bitwise Operators Bitwise mathematical operations can be somewhat
confusing to new robot programmers primarily because they are not taught in introductory
programming courses or explained in introductory programming texts. This is
unfortunate because understanding how to manipulate bits in the programming language is
critical for robotics programming. Some languages simplify the task of accessing bits by the
use of a single bit data type, while others do not provide you with any data types smaller
than a byte (eight bits).
The reason why manipulating bits in robots is so important is due to the organization of
control bits in the controlling computer systems. Each I/O port register variable address will
consist of eight bits, with each bit being effectively a different numeric value (listed in Table
13-4). To look at the contents of an individual bit, you will have to isolate it from all the others
using the bitwise AND operator:
TABLE 13-4 Different Bits in a Byte and Their Numeric Values
Looking at this for the first time, it doesn't make a lot of sense although when you consult
with Table 13-4, by looking at the binary value you can see that the value of 16 just has
one bit of the byte set to 1 and when this is ANDed with the contents of the register, just
this one bit's value will be accurate—all the others will be zero.
The set bit value that isolates the single bit of the byte is known as a mask. You can either
keep a table of mask values in your pocket at all times, or you can use the arithmetic value
at the right of Table 13-4. The shift left (<<) operation of one bit is equivalent to finding the
set power of 2 or using one of the binary, hex, or decimal values in the table—you just don't
have to do any thinking to use it.
To show how the arithmetic value is used to facilitate writing a 1 in a bit of a register, you
could use the assignment statement and expression:
Register = (Register & ($FF ^ (1 << Bit))) | (1 << Bit)
The expression first calculates the byte value with Bit set and then XORs it with all bits set
to produce a mask, which will allow the value of each bit of the register to pass unchanged
except for Bit, which becomes zero. The register value with Bit zero is then ORed with the bit set and the resulting value is stored in Register. The parentheses, while seemingly complex,
force the expression to execute as desired.
13.1.5 ARRAYS AND CHARACTER STRINGS
A variable is normally assigned to a specific memory location within the computer that cannot
change. For many kinds of data, this is acceptable, but there will be cases when you
would like to access a data address arithmetically rather than having a fixed address. The
array variable modifier provides you with a number of different variables or elements, all
based on a location in memory and given the same name, but accessed by their address
within the variable.
Fig. 13-3 shows how memory is used to implement an array of bytes. The actual byte (or
array element) is selected by adding an index to the variable name. Normally the index is
added to the address of the variable name, so the first index is zero. To read the third byte
in the example array and store it in another variable, the following assignment statement
could be used:
Writing to an array's is carried out exactly the same way. Instead of explicitly specifying the
arrays index, you can calculate it arithmetically using an expression. For example, the value
47 is written to the seventh element if i is equal to three:
Arrays are often used to implement a string of characters. A string is simply a sequence
of alphabetic or numeric characters implemented as a series of incrementing array elements.
Most strings are of the ASCIIZ type, which means that they consist of a number of ASCII
characters and end with the ASCII NULL character (hex $00).
Depending on the programming language, you may be able to access a string like a single
element variable or as an array of characters. The BASIC language handles strings as a
single element variable, which means you can read and write to them without any special
functions or operators. The C language requires the programmer to treat strings of characters
as an array and each array element must be handled separately. To simplify the amount
of work required to deal with strings in C, there are a number of standard library routines
written for it, but new programmers will find working with strings in C challenging.
13.1.6 DECISION STRUCTURES
If you are familiar with programming, when you skim over this section you might think that
decision structures is a fancy euphemism for if and other conditional execution statements.
That would be an unfortunate conclusion because it simplifies the different structures and
what can be done with them. Decision structures are the basis of structured programming
and were invented to simplify the task of programming and reading code.
The decision structures all avoid the use of the goto statement. This is important because
gotos can make code difficult to read and more difficult to write. The issue is that gotos have
to have somewhere to go to—either an address, line number, or label. Using only decision
structures in your programming avoids this requirement and allows you to concentrate on
the program instead of trying to remember if you have used a label before. Even though
decision structures and structured programming are considered advanced programming
topics, by using them your programs will actually be more simple to create.
The first decision structure to be aware of is the if statement, which is often written out
in the form if/else/endif because these are the three statements that make up the decision
structure that executes if a set of conditions is true. If a specific number of statements are to
execute if the conditions are true, the statements
if (Condition)
Statement1
Statement2
:
endif
are used. The condition statement is normally in the form:
Variable|Constant Operator Variable|Constant
where the Operator can be one of the six comparison operators listed in Table 13-5. The
vertical bar (|) is an OR and indicates that either a variable or a constant can be placed at
this part of the condition. Note that the equals and not equals operators can be different
depending on the programming language used.
TABLE 13-5 Typical Comparison Operators |
OPERATOR |
FUNCTION |
|
=, == |
Returns “True” if the values on both sides are equal |
<>, != |
Returns “True” if the values are not equal |
> |
Returns “True” if the value on the left is greater than the one on the right |
>= |
Returns “True” if the value on the left is greater than or equal to the one on the right |
< |
Returns “True” if the value on the left is less than the one on the right |
<= |
Returns “True” if the value on the left is less than or equal to the one on the right |
|
The values on the left and right side of the comparison operator can also be arithmetic
expressions (i.e., "i + 4"), but when you first start programming, you should avoid making
the comparisons complex as it will make it more difficult for you to debug later.
Multiple comparisons can be put together in a comparison statement using the logical
AND and OR operators available in the programming language. Like adding arithmetic
expressions to comparisons, you should avoid putting in multiple comparisons in a single
statement until you are comfortable with programming.
An optional part of the if decision structure, the else statement, can be used to specify
statements that execute when the conditions are not true:
if (Condition)
Statement1
Statement2
:
else
Statement1
Statement2
:
endif
Along with executing some statements if conditions are true, you can also repeatedly execute
instructions while a condition is true using the while statement in which the condition is
exactly the same as the if statement. When the endwhile statement is encountered, execution
jumps back up to the original while statement and re-evaluates the condition. If it is true, the
statements inside while and endwhile repeat, else the statements after the endwhile execute.
while (Condition)
Statement1
Statement2
:
endwhile
There are many forms of the while statement, including the until statement, which continues
looping while the condition is not true and stops looping when the condition becomes
true. These different types of statements are specific to the programming language.
The final type of decision structure that you should be aware of is the select or switch
statements which take the form:
select (Variable)
case Constant1:
Statement1
Statement2
:
case Constant2:
Statement1
Statement2
:
:
endselect
The select/switch statements allow you to avoid multiple if statements for different values
of a variable. Usually the case value is a constant, but in some programming languages
it can be a variable, a range of values, or a set of conditions.
When you look at these examples and those throughout the book, you should notice that
the code is indented to different points depending on whether it is part of a decision statement.
This indentation is a programming convention used to indicate that the code is part
of a conditional operation. You should make sure that you indent your code in a manner
similar to that shown in this book to make your program easier to read and understand
when you are trying to figure out what is happening for a specific set of conditions.
13.1.7 SUBROUTINES AND FUNCTIONS
One of the first things a programmer does when starting on a project is to map out the individual
segments, or subroutines and functions (sometimes simply called routines) that make
up the application. A subroutine is a block of code that can be selectively executed by calling it. Multiple calls can be placed throughout a program, including calls from other subroutines.
Subroutines are meant to replicate repeated code, saving overall space in an application,
as well as eliminating the opportunity that repeated code is keyed in incorrectly. Even
the longest, most complex program consists of little more than bite-sized subroutines. The
program progresses from one subroutine to the next in an orderly and logical fashion.
A subroutine is any self-contained segment of code that performs a basic action. In the
context of robot control programs, a subroutine can be a single command or a much larger
action. Suppose your program controls a robot that you want to wander around a room,
reversing its direction whenever it bumps into something. Such a program could be divided
into three distinct subroutines:
- Subroutine 1. Drive forward. This is the default action or behavior of the 'bot.
- Subroutine 2. Sense bumper collision. This subroutine checks to see if one of the bumper
switches on the robot has been activated.
- Subroutine 3. Reverse direction. This occurs after the robot has smashed into an object,
in response to a bumper collision.
There are two different ways to implement a subroutine in a programming language.
The first is to call a label, which executes until a return statement is executed. The second
way is to create a procedural subroutine, which is physically separate from the caller. The
first method is implemented directly in code like:
This is the simplest implementation of a subroutine and is used in many beginner programming
languages, including PBASIC.
Procedural subroutines are physically separate from the executing code. In the previous
code example, if execution continues it will execute the code at Routine1 without calling it.
After executing the code of Routine1, it will attempt to return to the statement after the call
statement and could end up executing somewhere randomly in the application and will definitely
execute in a way that you are not expecting.
A consequence of being physically separate from the caller, a procedural subroutine will
have to have different parameters passed to it, which will be used by the subroutine. These
parameters are the input data for the subroutine to execute; in the simple call label type of
subroutine, the parameters are the program variables that are shared between the main line
of the program and the subroutines. The procedural subroutine looks like:
Looking at this example, the values of Parameter1 and Parameter2 are unique to
PRoutine1 and the instance in which it is being called. They are known as local variables
and, along with any other variables declared inside the procedural routine, can only be
accessed by code within this routine. Global variables are declared outside of any procedure
and can be accessed by any subroutine in the application.
While the parameters were described as a consequence of procedural subroutines, they
are actually an advantage because they eliminate the need for keeping track of the global
variables used as parameters and making sure they are not inadvertently changed in the
program. Rather than being a consequence, the parameters and local variables are actually
an advantage as they will make your software easier to write.
Changing a variable value in a straight call/return subroutine is quite simple and can be
accomplished in a procedural subroutine by accessing a global variable. A better way of
changing a variable value in a procedural language is to use a function, which is a special
type of subroutine that returns a value to the caller. For example:
While execution returns to the statement after the function call, the Variable assignment
takes place when execution returns from the function and before it resumes on the statement
after the function call. Using functions to return a new value instead of subroutines,
which update a common global variable, makes seeing the operation of the code much
more obvious and avoids the possibility that the global variable is changed incorrectly by
another subroutine.
Your PC's console is the screen and keyboard used to enter data and display information.
At first thought, console I/O is not very useful for robotics developers—the robot is not
going to have a direct connection to a computer at all times and the extra work doesn't
seem justifiable.
These statements are not completely accurate; knowing how to implement console I/O
can be very useful to robot designers as they debug their creations and experiment with different
ideas.
One important point to make is that the term console is used to describe a monochrome
text display with a straight ASCII keyboard. You should not have to worry about displaying
graphics and handling mouse inputs and control (unless you want to). The basic console is
an 80 character by 24 line display. Data can be formatted specially on the screen, but for
the most part, it is a line of text output using the programming languages built-in print
function.
Data input can be quite complex and use the cursor control keys on your keyboard, but
you should just input data to the console a line at a time with the data being accepted when
the enter key is pressed. Waiting for the enter key to be pressed simplifies the data input,
allows the use of the backspace key, and allows for the use of an InputString built-in function
of the programming language.
The simplest way to implement console I/O on a robot is to use a serial RS-232 connection
between the robot and the PC. There are a number of downloadable terminal emulators
for the PC, which will provide the console function as a separate window on your PC,
allowing you to communicate with your robot or computer circuits with virtually no disruption
of the operation of your PC.
Comments are used by a programmer as remarks or reminders of what a particular line of
code or subroutine is for. The comments are especially helpful if the program is shared
among many people. When the program is compiled (made ready) for the computer or microcontroller, the comments are ignored. They only appear in the human-ready source
code of your programs.
To make a comment using BASIC, use the apostrophe (') character. Any text to the right
is treated as a comment and is ignored by the compiler. For example:
' this is a comment
Note that the symbol used for comments differs between languages. In the C programming
language, for instance, the characters // are used (also /* and */ are used to mark a
comment block).
13.2 Robotics Programming
When programming is first taught, the concept that a program follows the "input—
processing—output" model is used (Fig. 13-4) in which data inputs to the program are
passed to a processing block and then passed out of the program in the form of outputs.
This model is good for initial programs on a PC in which some number crunching is done
to help you learn how the different programming statements work, but they have little relevance
when programming robots.
Instead, a programming model like the one shown in Fig. 13-5 should be used. In this
model, the program is continually looping (never ending) and reading (or polling) inputs,
passing them to a block of code for processing into outputs and then delaying some amount
of time before repeating.
The delay block is critical for robot programming as it allows the code to be tuned for the
operation of the robot and its parts. If the delay is too short, the robot may vibrate more than
move because one set of commands from some input conditions are countermanded by the
next set of input conditions, resulting in the original input conditions are true again . . .
Specifying the appropriate amount of delay is something that will have to be found by
trial and error. The total loop time should be less than 1 s, but as to the best time, that is
something that you will have to find by experimenting with your robot. As a rule of thumb,
try to keep the total loop time at least 100 ms (0.1 s) so that the motors have time to start
up and initiate action before stopping and a new set of inputs polled.
You may also want to leave the motors running during the delay based on the assumption
that chances are the processed output will not change radically from loop to loop. This
will help make your robot move more smoothly, which is always desirable.
13.3 Graphical Programming
In this chapter, there is a lot of material on text-based programming that probably seems
very difficult and complex, especially when you consider that there are many graphical
robot programming environments available that could reduce a reasonably complex function
like programming a light-seeking robot into the simple chore of drawing a picture like
the one in Fig. 13-6.
This program will cause a robot to move toward the brightest point in the room. This is
a lot easier to understand than the text-based version, which would look something like
which would probably take you a lot longer to program than moving some blocks and lines
around in a graphic editor.
While being more difficult to understand and longer to develop, the text-based program
gives you a great deal of flexibility that you don't have with most graphical programming
environments. Both programs perform the same operations and work the same way, but
what happens if you discover that rather than turning as soon as the left and right light sensors are different values, the robot could run straight while they were within two values of
each other. In the graphical programming environment, this would be impossible, but in the
text-based program the two if statements could be changed to
if (Left > (Right + 2)
if ((Left + 2) < Right)
which would cause the robot to move forward if Left and Right were +/-2 of each other
rather than turning if they weren't exactly equal.
There are a lot of other cases where you will find that you need to tweak the program to
run optimally, but you find that it is impossible to modify the graphic program for these
needs.
Another advantage of text-based programming over graphic programming is the ability
to add more complex logic to the operation of the robot. For example, if you wanted the
robot to turn right if it has turned left five times in a row you can add the code quite easily
to the text program whereas the graphic program does not have that capability (and indeed,
very few graphical programming environments even have variables).
It is important to not generalize. While most beginner and hobbyist graphical programming
environments and languages do have the limitations listed here, more professional
ones do not. For example, National Instruments LabView programming environment offers
the same capabilities and flexibility as a text programming language despite being based on
just graphic symbols for operators, variables, and decision structures. Hopefully you realize
that these capabilities do not come free; creating a complex graphic program will require at
least the same amount of study and practice as developing a text-based one.
To learn more about . . . |
|
Read |
Programming a robot computer or microcontroller |
|
Chapter 12, "An Overview of Robot 'Brains' " |
Ideas for working with bitwise values |
|
Chapter 14, "Computer Peripherals" |
Programming using infrared remote control |
|
Chapter 16, "Remote Control Systems" |