The infrared beacon is a critical part of the RoboTag project and is easily
the most important aspect of the competition. This document details the
design and construction of a PIC-based infrared beacon that will detect up to
seven other beacons within 1/10th of a second. The beacons work within
line-of-sight, don't detect their own signal, and don't interfere with
most commercially available IR navigation sensors.
Infrared Light & Associated Problems
Infrared radiation lies between the visible and microwave portions of the
electromagnetic spectrum. We'll be using a detector that has peak sensitivity
at a wavelength of 940nm, so we'll use IR LEDs that emit at 940nm.
However, there are a number of problems with an infrared signal:
- a number of robots are using infrared navigation sensors
- fluorescent lights, the sun, cameras, etc, emit large amounts of IR
- infrared signals 'bounce' off surfaces
- (which is how IR navigation sensors work)
It's important to use modulated IR light to avoid interference from other
IR sensors and from lights, the sun, etc. For example, if we were using plain
infrared light (ie: we emitted light at 940nm), it would be very difficult to
determine the difference between another robot or a desk lamp. Modulated IR
is commonly used in IR navigation sensors.
To avoid conflicting with IR navigation sensors, we will be modulating our
infrared signal at 56.8kHz. Since we're interfacing with digital devices (and
we're not doing any mixing, filtering, etc), we'll use a square-wave signal.
So our modulated IR signal would look something like this:
There's still the problem of infrared signals bouncing off the arena walls,
which is difficult to address. If we use a material that doesn't reflect
infrared light then the IR navigation sensors won't work. The solution?
There isn't really one. Even slowly moving robots wouldn't see an infrared
reflection from another robot for very long, so it won't be too bad.
Robots which do see the reflection of another robot's beacon can obviously
use this to their advantage. The scenario above shows the robot on the right
seeing the signal from the robot on the left (and vice versa). Remember that
both robots won't be able to tell whether or not the other robot is in the
original location, or the mirrored location (shown in red).
The Technical Specification
The technical specification is based around the design objectives of the
beacon:
- robots must be able to detect signals from up to 7 other robots
- robots must be able to detect signals within 1/10th of a second
- robots must not detect their own signal
- the signal should only work within line-of-sight
- the signal must be detectable from 3 inches to 12 feet
- the signal must not interfere with any other sensor
In the previous section we addressed the interference and line-of-sight
requirements of the design.
When building the specification it was important to consider the number of
other robots that must be detected, and the time in which the detection must
occur. I used the 0.1 second detection time based on the average reaction time
of a human -- if we can react to something within 100msec, then our robots
should be able to do the same.
Having each beacon be able to detect 7 other beacons means that we can have
eight robots playing at a time! That was the maximum number of 'bots that I
could imagine in one 12'x12' arena. "Pandemonium" just isn't accurate
enough.
It was also important to ensure that a robot wouldn't be able to detect its
own beacon. Because the beacons reflect off the arena walls it is important
to turn off the beacon detector when emitting the beacon signal. This works
perfectly with the non-multitasking PIC microprocessor which can only perform
one task at a time anyway.
In regards to the detection range, I recommend multiple high-output IR LEDs
(like the one I recommend later in this document) driven with 50-100mA.
While the continuous rating on the LEDs is only 50mA, you could probably drive
them at 2A without much problem. Remember our 6.25ms bursts of IR are
modulated, so the LED wouldn't be on for very long. In my lab tests, I've
detected another beacon at 12'+ with as little as 60mA of LED current.
So the technical specification of the beacon is as follows:
- consecutively, each beacon must:
- emit 6.25ms of modulated infrared light
- 940nm light modulated at ~56.8kHz (55.5kHz is okay)
- emitted 360-degrees around the robot
(minimum of 50% beam power in any direction)
- must be detectable at 12+ feet with a standard device (50+mA/LED)
- looks for infrared light from another robot
(for N blocks of 6.25ms each, N is assigned by course coordinator)
- emit 6.25ms of modulated infrared light (as spec'd above)
- looks for infrared light from another robot
(for 14-N blocks of 6.25ms each)
- repeat the process
But this means that when the beacon is transmitting, it won't detect other
beacons that are also transmitting. (ie: the beacon can't 'talk' and 'listen'
at the same time) One way around this problem would be to synchronize the
beacons to start at the same time. This, however, is a real pain in the ass,
so we'll use a timing solution instead.
The timing solution (shown below) works if you consider the following
worst-case scenario. Assume all eight robots are within line-of-sight of each
other. Assume that, by luck, the first 6.25ms pulse of infrared light occurs
at the same time. By changing the time between pulses (ie: each robot waits a
different amount of time before sending out another pulse), we can ensure that
each robot will detect ALL the others, within 100ms.
This can be shown in a chart form as follows:

The coloured blocks indicate when the particular robot is transmitting, and
the white blocks indicate when the robot is 'looking'.
The above chart shows each robot transmitting from 0 to 6.25ms, then
'looking' for a differing amount of time before transmitting another 6.25ms
pulse. This allows us to have eight robots in the same area that will ALWAYS
detect each other within 100ms.
In case you're wondering, yes, that is the maximum number of robots that
can interact (given the 6.25ms operating time with a 100ms loop time).
If we added a ninth robot that transmitted from 0-6.25ms and from
56.25-62.5ms, it could 'collide' with robot #7.
An Example Solution
My proof-of-concept solution features two beacons that each have a
single detector and single emitter. Each beacon, detailed below, uses a
4MHz PIC to drive a single IR LED and detect a signal from a single LITEON
receiver. You will obviously want to extend my work to handle multiple IR
LEDs (additional hardware), and multiple receivers (additional hardware
and software). You should consider using the 20MHz PIC16F84 to interface
with more than one detector.
The schematic, below, shows how the PIC hardware interfaces to the
LITEON IR detector module (LTM-97AS-56) via RA0. Note the power supply
noise suppression in the RC filter connected to the LITEON detector. The
PIC drives a red LED whenever another beacon is detected - this output is
connected to RB2.
The PIC also drives the IR LED, connected to RB0, via a simple BJT. I
use a 1kohm resistor to limit the current required to drive the
transistor, and a 39ohm transistor to limit the current flowing through
the IR LED. You will need to develop a more robust biasing network for
additional LEDs, of course.
Beacon schematic:
The assembly language source code, shown below, has been assembled to a
HEX file that can be downloaded in the form of a zipfile: beacon.zip, 12Kb. The source is also shown
below:
NOTE: The code below is written for a PIC16F84A with a 4.0MHz
resonator. If you add additional inputs, remember that the PIC is a CMOS
device and all inputs must go somewhere!
; beacon.asm
;
; Written Jan 2-5th, 2001 by wsitch@engsoc.carleton.ca
; Copyright (c) 2001 by William Sitch. All rights reserved.
;
; RoboTag information: http://robotag.carleton.ca/
;
; operates on a 100ms cycle (detection in 100ms)
; 1x6.25ms process.......: drives an IR beacon at 55.5kHz
; Nx6.25ms processes.....: looks for another beacon
; 1x6.25ms process.......: drives an IR beacon at 55.5kHz
; (14-N)x6.25ms processes: looks for another beacon
;
; N={0..7}, use a different value for each co-existing beacon
;
;
; initialize
;------------
list p=16f84a ; initialize to the correct PIC type
radix hex ; default to HEX format
;
; MPASM configuration
;---------------------
__config H'3FF9' ; set the configuration bits
; CPoff, PWRTEoff, WDToff, XTosc
;
; compiler equates
;------------------
STATUS equ 0x03
PORTA equ 0x05
PORTB equ 0x06
W equ 0x00
F equ 0x01
Z equ 0x02
C equ 0x00
;
LITEON equ 0x00 ; pin0 on porta is LITEON IR input
LEDout equ 0x00 ; pin0 on portb is IR LED output
Tdetect equ 0x02 ; pin2 on portb is target detect output
;
nsamprq equ 0x04 ; 5-6/6 samples must see IR to inc(avgIR)
nIRreq equ 0x78 ; 120/249 chkIRs see avgIR to see target!
;
; define variables
;------------------
n55ks equ 0x0C ; number of 55kHz oscillations left
nchks equ 0x0D ; number of chkblip executions left
avgIR equ 0x0E ; number of 25us chkIRs that see avgIR
nsamp equ 0x0F ; number of samples that see IR
tdetect equ 0x10 ; target detected (0F / 1T)
;
;
; define reset instructions at 0x000
;------------------------------------
org 0x000
reset
goto start
;
; define the interrupt start at 0x004
;-------------------------------------
org 0x004
start
;
; main code
;-----------
movlw b'00000001'
tris PORTA ; porta: pin0 input, others output
movlw b'00000000'
tris PORTB ; portb: all output
; make the first 'blip'
; 2us in goto at end of loop
blip call doblip ; +6.248ms = 6.250ms total
; look for other 'blips'
; *** change this to alter the timing of your beacon!
; *** (but ensure that a total of 14 seeblips are called)
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
; make the second 'blip'
nop
nop ; 2us, to even out the 'goto blip'
call doblip ; +6248us = 6.250ms total
; look for other 'blips'
; *** change this to alter the timing of your beacon!
; *** (but ensure that a total of 14 seeblips are called)
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
call seeblip ; 6.250ms total
; do it all again
goto blip ; 2us (+6248 in next call)
; doblip -- generates 346 55.5kHz square waves (346*18us=6.228ms)
;--------
doblip ; [2us] call
movlw 0xFF
movwf n55ks ; 2us, puts 255 into n55ks
osc nop ; 1us, delay to make 4us (in osc loop)
call make55k ; 14us, oscillate at 55.5kHz, 4us needed
decfsz n55ks,F ; 1us, decs n55ks, skip next if == 0
goto osc ; 2us, repeat
; we've created 255 oscillations for a total
; of 4589us (the last loop decfsz takes 2, no goto)
morblip ; we need 2us more for the prev. osc
movlw 0x5B
movwf n55ks ; 2us, puts 91 (346-255) into n55ks
oscmore call make55k ; 14us, oscillate, baby! 4us needed
nop ; 1us
decfsz n55ks,F ; 1us, decs n55ks, skip next if ==0
goto oscmore ; 2us, repeat
; we've performed 91 more oscillations for
; 1637us (the last loop decfsz takes 2, no goto)
call delay8u
nop
nop
nop
nop
nop ; 13us
bcf PORTB,Tdetect ; 1us, turn off the target detect
return ; [2us] return, 6246us+7us=6253us!
; make55k -- generates a 55.5kHz square wave
make55k bsf PORTB,LEDout ; 1us, sets the output = 1
call delay8u ; eats up 8us, 9us total
bcf PORTB,LEDout ; 1us, sets the output = 0
return ; 2us return, 2us call, 4 missing
; delay8u -- pauses for 8usec total, including the call & return
delay8u nop ; 3us + 2us call (PC changes)
nop ; 4us
nop ; 5us
nop ; 6us
return ; 8us total, when returned
; seeblip -- performs 249 25us chkIRs (249*25us=6225us)
;---------
seeblip ; [2us] call
clrf avgIR ; 1us, sets avgIR = 0
movlw 0xF9
movwf nchks ; 2us puts 249 into nchks
chk call chkIR ; 22us, counts avgIR blips
decfsz nchks,F ; 1us, decs nchks, skip next if ==0
goto chk ; 2us, repeat
; now avgIR has value 0..249, the number of times that
; chkIR found nsamp>nsamprq (over six measurements)
; (it took 6224us - the last cycle takes 24us)
movf avgIR,W ; 1us, puts avgIR into W
sublw nIRreq ; 1us, W = nIRreq - avgIR
; if W<0, target detected!
btfss STATUS,C ; 2us (1us) skip if C=1: avgIR<=nIRreq
goto detectd ; (2us) goto detectd if C=0: avgIR>nIRreq
;no enemy detected
bcf PORTB,Tdetect ; 1us, clear detect bit
goto chkdone ; 2us
;enemy detected!
detectd bsf PORTB,Tdetect ; 1us, set detect bit
nop ; kill time to even things out
chkdone ; <6237us>
call delay8u ; 8us
nop
nop
nop
nop
return ; [2us] return, 6250us exactly!
; chkIR -- takes six measurements and compares results with nsamprq
; if nsamp>nsamprq, then avgIR = avgIR + 1
chkIR ; [2us] call
clrf nsamp ; 1us, nsamp=0
; <3us>
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
; <7us>
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
; <11us>
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
btfss PORTA,LITEON ; 2us (1us) skips if LITEON=1 (no IR)
incf nsamp,F ; (1us) adds one to nsamp if liteon=0!
; <15us>
nop ; throw away a cycle
; <16us>
movf nsamp,W ; 1us, puts nsamp into W
sublw nsamprq ; 1us, W = nsamprq - nsamp
; if W<0, avgIR detected
btfss STATUS,C ; 2us (1us) skip if C=1: nsamp<=nsamprq
incf avgIR,F ; (1us) set avgIR+=1 if C=0: nsamp>nsamprq
; <20us>
return ; [2us] return
end
; end of beacon.asm
The code above is fairly simple: the function doblip makes
6.250ms of modulated IR light. The PIC outputs a square wave signal with
an 18us period - which corresponds with 55.5kHz, which is acceptable for
our needs. doblip actually creates 346 oscillations (346*18us =
6.228ms) and the overhead uses up the remaining 22us.
The seeblip function, above, interfaces with the LITEON device
to detect another beacon. Each seeblip function operates for
exactly 6.250ms, and takes 249 samples. Each sample, a function call to
chkIR, is 25us in length and consists of 6 measurements. This
requires 249*25us = 6.225ms, and the overhead uses up the remaining
25us.
If a chkIR function measures 5 or 6 low (ie: 0) values from the
LITEON, indicating that modulated IR is present, then that particular
sample is assumed to have detected part of an IR beacon. The number of
samples that detect IR is counted, and a positive detection is made when
more than 120 of 249 samples detect IR.
In order to tighten or relax the required amount of IR to signal a
detection, the programmer should modify the nsamprq (and maybe the nIRreq)
variables, as follows:
- The nsamprq variable indicates how many measurements must detect IR
for the cluster to 'detect' part of a signal. If you set nsamprq to 4
(default), then you require 5 or 6 (out of 6) measurements to see IR.
This means 2/3 of the 25us sample must see IR.
- The nIRreq variable indicates how many samples are required to
'detect' a beacon signal. If you set nIRreq to 120 (default), then you
require at least 120 chkIR function calls to measure more than nsamprq
instances of IR. This means a little less than 1/2 of the 6.250ms must
see IR.
Note that if the nIRreq variable is greater than 121 then it might
be possible to not detect another beacon! This can be shown as
follows. If we assume that two beacons, #6 and #7 in the timing diagram
above, are perfectly NOT synchronized, we might expect the following
signal overlap:
This means that robot #7 would transmit for the first half of robot
#6's first pulse. So #7 would only see the second half of #6's
pulse. This means that we must program our detectors to look for this
worst-case scenario, where we would only see two half-pulses from another
beacon.
When re-working the above code, take care to observe the timing
requirements detailed in this document. Every 'block' of time, whether
the PIC is emitting or detecting, should be exactly 6250us, including the
time to call and return from the function. In order to allow others to
lock onto the 100ms repeating signal, the timing MUST be as close to
perfect as possible. This will be checked during the software review
phase of the marking.