Library files provide standard C functions for interfacing with hardware on the robot controller board. These functions are written either in C or as assembly language drivers. Library files provide functions to do things like control motors, make tones, and input sensors values.
IC automatically loads the library file every time it is invoked. Depending on which 6811 board is being used, a different library file will be required. IC may be configured to load different library files as its default; for the purpose of the 6.270 contest, the on-line version of IC will be configured appropriately for the board that is in use.
As of this writing, there are five related 6811 systems in use: the 1991 6.270 Board (the "Revision 2" board), the 1991 Sensor Robot, the Rev. 2.1 6.270 Board (from 1992), the Rev. 2.2 6.270 Board (from 1993), and the Rev. 2.21 6.270 Board (from 1994). This writing covers the Rev. 2.21 board only; documentation for the other systems is available elsewhere.
On the MIT Athena system, IC library files are located in the following directory:
`/mit/6.270/lib/ic'
To understand better how the library functions work, study of the
library file source code is recommended. The main library file for
the Rev. 2.2 6.270 Board is named lib_r22.lis
.
Motor ports are numbered from 0 to 5; ports for motors 0 to 3 are located on the Microprocessor Board while motors 4 and 5 are located on the Expansion Board.
Motor may be set in a "forward" direction (corresponding to the green motor LED being lit) and a "backward" direction (corresponding to the motor red LED being lit).
The functions fd(int m)
and bk(int m)
turn motor m
on forward or backward, respectively, at full power. The function
off(int m)
turns motor m
off.
The power level of motors may also be controlled. This is done in
software by a motor on and off rapidly (a technique called
pulse-width modulation. The motor(int m, int p)
function
allows control of a motor's power level. Powers range from 100
(full on in the forward direction) to -100
(full on the the
backward direction). The system software actually only controls
motors to seven degrees of power, but argument bounds of $-$100 and
$+$100 are used.
void fd(int m)
m
on in the forward direction.
Example: fd(3);
void bk(int m)
m
on in the backward direction.
Example: bk(1);
void off(int m)
m
. Example: off(1);
void alloff()
void ao()
ao
is a short form
for alloff
.
void motor(int m, int p)
m
at power level p
.
Power levels range from 100
for full on forward to -100
for
full on backward.
Servos are motors with internal position feedback which you can accurately command to a given orientation. Servos will actively seek to move to and remain at the orientation they are commanded to go to. Servos are useful for aiming sensors or moving actuators through a limited arc. They are generally able to sweep through about 180 degrees and no more.
Library routines allows control of a single servo motor. The servo motor has a three-wire connection: power, ground, and control. There is a dedicated connection for the servo on the main board at the top of the bank of connectors which are above and to the left of the main power switch. A three prong connector with ground on the left, power in the middle, and control on the right should be used to plug the servo into its connector. So long as you are sure to get power in the middle, the servo will not be damaged by plugging it in backwards, but will simply not work until it is plugged in properly.
The position of the servo motor shaft is controlled by a rectangular waveform that is generated on the A7 pin. The duration of the positive pulse of the waveform determines the position of the shaft. The acceptable width of the pulse varies for different models of servos, but is approximately 700 timer cycles minimum and 4000 timer cycles maximum, where the 6811's timer runs at 2MHz. The pulse is repeated approximately every 20 milliseconds.
void servo_on()
void servo_off()
int servo(int period)
period
timer cycles so long as that falls within the acceptable range for the
servo. Otherwise it trunctates the value to the closest the servo
is physically able to go to. It returns the thresholded version of
the period you gave it. Remember that servos have a finite
reaction time which, while very fast to human senses of time, is
very slow to a processor. If you are resetting the servo angle
in a tight loop it may well never catch up with you.
int servo_rad(float angle)
pi
radians.
int servo_deg(float angle)
int radian_to_pulse(float angle)
int degree_to_pulse(float angle)
There are two output ports located on the Expansion Board that are suitable for driving LEDs or other small loads. These ports draw their power from the motor battery and hence will only work when that battery is connected.
The following commands are used to control the LED ports:
void led_out0(int s)
s
is non-zero; turns it
off otherwise.
void led_out1(int s)
s
is non-zero; turns it
off otherwise.
Motor ports 4 and 5, located on the Expansion Board, may also be used to control unidirectional devices, such as a solenoid, lamp, or a motor that needs to be driven in one direction only. Each of the two motor ports, when used in this fashion, can independently control two such devices.
To use the ports unidirectionally, the two-pin header directly beneath the motor 4 and 5 LEDs is used.
void motor4_left(int s)
s
is
non-zero; turns it off otherwise.
void motor4_right(int s)
s
is
non-zero; turns it off otherwise.
void motor5_left(int s)
s
is
non-zero; turns it off otherwise.
void motor5_right(int s)
s
is
non-zero; turns it off otherwise.
int digital(int p)
p
, as a true/false value (1 for true and 0 for false).
Sensors are expected to be active low, meaning that they are
valued at zero volts in the active, or true, state. Thus the library
function returns the inverse of the actual reading from the digital
hardware: if the reading is zero volts or logic zero, the
digital()
function will return true.
int dip_switch(int sw)
sw
on interface
board. Switches are numbered from 1 to 4 as per labelling on actual
switch. Result is 1 if the switch is in the position labelled "on,"
and 0 if not.
int dip_switches()
int choose_button()
/* wait until choose button pressed */ while (!choose_button()) {}
int escape_button()
/* wait for button to be pressed; then wait for it to be released so that button press is debounced */ while (!escape_button()) {} while (escape_button()) {}
int analog(int p)
p
.
Result is integer between 0 and 255.
If the analog()
function is applied to a port that is
implemented digitally in hardware, then the value 255 is returned if
the hardware digital reading is 1 (as if a digital switch is
open, and the pull up resistors are causing a high reading), and the
value 0 is returned if the hardware digital reading is 0 (as if a
digital switch is closed and pulling the reading near ground).
Ports are numbered as marked on the Microprocessor Board and Expansion
Board.
int frob_knob()
int motor_force(int m)
m
. Result is integer between 0 and 255, but
typical readings range from about 40 (low force) to 100 (high force).
The force-sensing circuitry functions properly only when motors are
operated at full speed. The circuit returns invalid results when
motors are pulse-width modulated because of spikes that occur in the
feedback path.
The force-sensing circuitry is implemented for motors 0 through 3.
The infrared subsystem is composed of two parts: an infrared transmitter, and infrared receivers. Software is provided to control transmission frequency and detection of infrared light at two frequencies.
void ir_transmit_on()
void ir_transmit_off()
void set_ir_transmit_period(int period)
period
determines the delay in half.microseconds between
transitions of the infrared waveform. If period
is set to
10,000, a frequency of 100 Hz. will be generated. If period
is
set to 8,000, a frequency of 125 Hz. will be generated. The decoding
software is capable of detecting transmissions on either of these two
frequencies only.
void set_ir_transmit_frequency(int frequency)
frequency
is measured in hertz.
Upon a reset condition, the infrared transmission frequency is set for
100 Hz. and is disabled.
In a typical 6.270 application, one robot will be broadcasting infrared at 100 Hz. and will set its detection system for 125 Hz. The other robot will do the opposite. Each robot must physically shield its IR sensors from its own light; then each robot can detect the emissions of the other.
The infrared reception software employs a phase.locked loop to detect infrared signals modulated at a particular frequency. This program generates an internal squarewave at the desired reception frequency and attempts to lock this squarewave into synchronization with a waveform received by an infrared sensor. If the error between the internal wave and the external wave is below some threshold, the external wave is considered "detected." The software returns as a result the number of consecutive detections for each of the infrared sensor inputs.
While enabled, the infrared reception software requires a great deal of processor time. Therefore, it is desirable to disable the IR reception whenever it is not being actively used.
Up to four infrared sensors may be used. These are plugged into positions 4 through 7 of the digital input port. These ports and the remainder of the digital input port may be used without conflict for standard digital input while the infrared detection software is operating.
The following library functions control the infrared detection system:
void ir_receive_on()
void ir_receive_off()
void set_ir_receive_frequency(int f)
f
should be 100 for 100 Hz. or 125 for 125
Hz. Default is 100.
int ir_counts(int p)
p
of the digital input
port. Result is number from 0 to 255. p
must be 4, 5, 6, or 7
Random noise can cause spurious readings of 1 or 2 detections. The
return value of ir_counts()
should be greater than three before
it is considered the result of a valid detection. You must wait
at least 100 milliseconds after starting the reception before the
ir_counts()
data is valid.
Shaft encoders can be used to count the number of times a wheel spins, or in general the number of digital pulses seen by an input. Two types of shaft encoders can be made using 6.270 sensors: optical encoders which use optical switches whose beam is periodically broken by a slotted wheel, or magnetic encoders which uses hall effect sensors which change state when a magnet on a shaft rotates past.
Shaft encoders are implemented using the input timer capture feature on the 6811. Therefore processing time is only used when a pulse is actually being recorded, and even very fast pulses can be counted. Because digital ports 0 and 1 are the only two input capture channels available for use on the 6.270 board, only two channels of shaft encoding are possible.
The encoding software for the 6.270 board keeps a running count of the number of pulses each enabled encoder has seen. The number of counts is set to 0 when a chanel is first enabled and when a user resets that channel. Because the counters are only 16-bits wide, they will overflow and the value will appear negative after 32,767 counts have been accumulated without a reset.
As shaft encoders are an optional feature and not part of the standard hardware of the 6.270 board, the library routines which read them are not loaded on start up.
In order to load the following routines for use in your programs, load
the file encoders.lis
. This file is in the standard 6.270
library directory so IC will find it by this name.
The actions of the shaft encoders are commanded and the results are
read using the following routines. The argument encoder
to each
of the routines specifies which shaft encoder the function should
affect. This value should be 0 for digital port 0 or one for digital
port 1. Arguments out of the range 0 to 1 have no useful effect.
void enable_encoder(int encoder)
void disable_encoder(int encoder)
void reset_encoder(int encoder)
enable_encoder()
to clear it.
int read_encoder(int encoder)
System code keeps track of time passage in milliseconds. Library functions are provided to allow dealing with time in milliseconds (using long integers), or seconds (using floating point numbers).
void reset_system_time()
long mseconds()
reset_\-system_\-time()
. mseconds()
is implemented as a C primitive (not as a library function).
float seconds()
void sleep(float sec)
sec
seconds. sec
is a floating point
number.
Example:
/* wait for 1.5 seconds */ sleep(1.5);
void msleep(long msec)
msec
milliseconds. msec
is a long integer.
Example:
/* wait for 1.5 seconds */ msleep(1500L);
Two simple commands are provided for producing tones on the standard beeper.
void beep()
void tone(float frequency, float length)
frequency
Hertz for
length
seconds. Returns when the tone is finished. Both
frequency
and length
are floats.
In addition to the simple tone commands, the following functions can
be used asynchronously to control the beeper driver.
void set_beeper_pitch(float frequency)
frequency
Hz.
The subsequent function is then used to turn the beeper on.
void beeper_on()
beeper_off
function is executed.
void beeper_off()
These functions are not loaded automatically, but they are available for you to use if you wish in the standard 6.270 library directory. They provide a standardized user interface for prompting users for input using the choose and select buttons and the frob knob. You may wish to use this library for debugging the state of your robot while away from the terminal or for changing thresholds or gains on the fly.
Load menu.c
to be able to use these functions.
int select_string(char choices[][],int n)
char a[3][14]={"Analog Port ","Digital Port ","Quit"}; int port,index=select_string(a,3); if(index>-1 && index<2) port=select_int_value(a[index],0,27);
int select_int_value(char s[],int min_val,int max_val)
float select_float_value(char s[],float min_val,float max_val)
min_val
and max_val
which is selected by
adjusting the frob knob until the appropriate value is displayed
then pressing a button. If the escape button was pressed,
returns -1 (or -1.0) regardless of the value chosen. Otherwise
returns the chosen value. Remember that the frob knob only returns
one of 255 values, so if the range is greater than that not all
values will be possible choices.
int chosen_button()
int wait_button(int mode)
mode
then returns which button was
pressed. The choices for mode
are: DOWN_B -- wait until either
button is pressed; UP_B -- wait until no buttons are pressed;
CYCLE_B -- wait until a button is depressed and then all depressed
buttons are released before returning.
Load menu.c
and diagnostic.c
to be able to use these functions.
You can easily copy diagnostic.c
and modify the
control_panel
function to call your own routines.
void control_panel()
int view_average_port(int port,int samples)
samples
readings
together, then prints and returns the average result. If the button
pushed was the ecape button, it returns -1.
void view_inputs()
void frob_outputs()