Some experiments about (simple) optical positioning in the living room.

NOTE 5/2012:
   I deleted most of the drivel in the "TX1-section" (*1*).
   Although some information might be missing right now, it reads
   a little easier...


  • coded IR beacons
  • real-time, 4 channel directional receiving pattern
  • beacon messages (pro version)
  • external beacon communications interface (pro version)
  • measuring distance to single beacon (pro version)
  • "easy" (...) to build (reduced version)
  • some more "blabla" I forgot to put in here...
  • ...

This minimal positioning system consists of three parts:

  • TX1/2: transmitting beacons
  • RX1/2: directional receiving circuit
  • MX1:   omni-directional motor mount (radar; pro version, not presented here)


Less drivel than before... (*1*)

The TX1 part of RayDialer, at least like presented here, consists of 3-12 IR LEDs, emitting base band amplitude modulated light. The modulation can chosen to be:
  • a) pure analog sine waves (standard)
  • b) digital (on/off)
  • c) digital PWM
  • d) single or multi frequency
  • e) ...

Right from the start, RayDialer-TX1 was planned to emit more than only one frequency component. This reduces detrimental effects from other, interfering light sources and adds a little more confidence to the received and analyzed signal.

Although the TX1 PCB (a little, overengineered multi-purpose device) is prepared for a PIC, all tests and further experiments were done with a ready-to-use DTMF "encoder".

There are a lot of ready to use DTMF chips available. I decided to use a HT9200. It can be operated in parallel or serial input mode. Parallel mode only requires four pull-up or -down resistors to select one of the 16 different DTMF tone combinations. Additionally, a chip enable pin can turn the output on or off.
In its serial mode, the HT9200 can be hooked up to a microcontroller.

       Complete DTMF Frequency Table
           1209Hz 1336Hz 1477Hz 1633Hz
     697Hz    1      2      3      A
     770Hz    4      5      6      B
     852Hz    7      8      9      C
     941Hz    *      0      #      D

Because the light intensity of an LED is (almost) direct proportional to the current, flowing through it, we need a voltage to current "converter".
The circuit on the right represents the absolute minimum, achieving this requirement.

The signal output of the HT9200 contains a DC offset of about 1/2*Vcc. The overlaying AC "audio" (shall I say optical, here? ;-) signal itself, is about 1Vpp (no load; see screenshot lower left).
A closer view reveals the discrete steps of the internal D/A converter (screenshot mid, right), they will be filtered out be the RC combination R2, C1 (fc=3.4kHz, can be lowered).

Despite the non-linear behaviour of the transistor Q1, the current flow through LED1 will be proportional to the voltage output of the HT9200. A coarse approximation (DC only):

Iled = (Udtmf - Ube) / R1
<=> Iled = (2.5V -0.65V) / 82Ohm
<=> Iled = 23mA

HT9200 signal output; Vcc=5V
a closer view...
just another one

The preceding, minimal circuit has many flaws:

  • the DC voltage offset causes a constant current offset and is not independent from the AC part
  • Q1 will cause unwanted intermodulations and does not provide a regulation
  • only one LED (even it is a high-power type) can not illuminate 360° (except for additional optics)
  • depending on the amount of LEDs, +Ub has to be chosen carefully (power dissipation Q1)
  • ...
But it may help getting quick "lab table results".

The full featured, all-inclusive test layout, which indeed contains much more stuff than a reduced-version-transmitter needs for operation, allows two basic LED orientations. As shown on the image at the right, the LEDs can be mounted horizontally, for direct receiver contact, or vertically, for indirect illumination of, e.g., a table tennis ball (or comparable ;-).

Each of the LEDs can be bypassed with a jumper. This comes in handy if the beacon is positioned in a corner or close to a wall. The circuit will automatically adjust the internal operating voltage to match the amount of LEDs and keep the losses low.

Reduced versions can of course be operated with a single IR power LED, without the need for a switching regulator or all the other fancy stuff...


Note: For latest version, see download section at the bottom...

all-inclusive schematic...
... and test layout
the real TX1 hardware

         RayDialer TX1 Channel Settings
   Note: Switch pulls low, if ON.
    DIGIT     4   3   2   1    frequencies [Hz]
     1      ON  ON  ON  OFF      697 + 1209
     2      ON  ON  OFF ON       697 + 1336
     3      ON  ON  OFF OFF      697 + 1477
     4      ON  OFF ON  ON       770 + 1209
     5      ON  OFF ON  OFF      770 + 1336
     6      ON  OFF OFF ON       770 + 1477
     7      ON  OFF OFF OFF      852 + 1209
     8      OFF ON  ON  ON       852 + 1336
     9      OFF ON  ON  OFF      852 + 1477
     0      OFF ON  OFF ON       941 + 1336
     *      OFF ON  OFF OFF      941 + 1209
     #      OFF OFF ON  ON       941 + 1477
     A      OFF OFF ON  OFF      697 + 1633
     B      OFF OFF OFF ON       770 + 1633
     C      OFF OFF OFF OFF      852 + 1633
     D      ON  ON  ON  ON       941 + 1633

TX1 spectrum; measured across R20


RX1, The Beginning

RX1 detects the direction of one or more transmitter(s) by measuring the signal intensity at at four different angles. Thanks to a tiny, but powerful dsPIC, all channels are sampled simultaneously and analyzed by a real-time Goertzel-Algorithm.

If more than one TX1-beacon in DTMF-mode is in the reception range of the receiver, it can only distinguish those with unique frequencies:

  • 1, 5, 9, D
  • 4, 8, #, A
  • 7, 0, 3, B
  • *, 8, 6, A
  • ...

This issue got addressed with the TX1-RX2 combination (upcoming attraction).

The photodiodes used (SFH203FA), have a 50% intensity angle of +-20°. Each of them is mounted with an angular offset of 40° to the adjacent one. Theoretically, this results in a constant, summed up signal level across rotation.
In practice, it requires bending, twisting and slapping ("fiddling around with photodiode position") the diodes until they are where they belong.

The differential signal input of two (or more) adjacent diodes is not used for position detection, only for a quick, first "guess" across an angular span of 160°. For operation, only one diode would be required, but four speed up things dramatically...

RX1 schematic...
... and test layout

The circuit consists of four equal detection circuits (CH1-4).
A standard photo detector circuit (aka "I-U converter"), formed by one half of the MCP602 (R1, D1) directly feeds the A/D input of the dsPIC.

Because only a single supply is available, R2, R5 and C4 provide an 1.65V offset for the circuit. The output signal, including the offset, is filtered by R4 and C5 (arithmetic mean, time constant ~10s (a little large, I agree ;-)) and fed back to the negative input of the photodiode amplifier via the second half of the MCP.
This way, any (speak: most of the) DC offset, caused by ambient light, will be corrected to 1/2 of the supply voltage.

The dsPIC provides a serial (115k, 8N1), as well as an I2C interface. For NXT compatibility, choose R23 and R24 to 82k. For real world I2C interfaces, reduce them to ~2k2-10k.

The processor had some spare pins left, so a tiny LCD was added to the test layout. It has to be mounted via IC-sockets or stuff like this.

to be continued... (11/2010)

noisy signal; 5kSps; 0.2s; float

clean signal; 5kSps; 0.2s; integer

real HW/FW sweep; 5kSps; 0.2s; 1Vpp input

like above, enlarged

like above, enlarged

like above, enlarged
The Scilab scripts, whose produced the simulations and the dsPIC captured frequency sweep, can be downloaded here. They may provide a good start understanding (and fiddling around with) the Goertzel algorithm.

Firmware RX1

DTMF mode display

sweep display

5 bytes left; mission accomplished ;-)

Number of Goertzel steps (samples) and effects.
Download this Scilab script here, or use SiSeLi ;-)

Notice that the output values are NOT NORMALIZED (divided by the number of samples)!
Use the source ;-)

to be documented... (11/2010)

incredible, that's from 2010? (5/2012 ;-)


    HOTKEYS (UART, 115200,8N1 or I2C):

     ESC  stop (after current operation)

      d   DTMF mode, all channels (4), all frequencies (8)
      D   DTMF mode, single shot
      s   sweep mode
      S   sweep mode, single shot

      a   sweep output for all channels (only serial)
      0   sweep output for one channel only
      c   sweep channel selection (one channel); requires IDLE_STATE; followed by:
        1    select channel 1
        2    select channel 2
        3    select channel 3
        4    select channel 4
        ESC  aborts channel selection

      f   sweep frequency range selection; requires IDLE_STATE; followed by:
        1    select tone 1;   sweep f1-47Hz..f1+48Hz
        2    select tone 2;   sweep f2-47Hz..f2+48Hz
        8    select tone 8;   sweep f8-47Hz..f8+48Hz
        a    select tone 1..8 sweep f1-47Hz..f8+48Hz
        ESC  aborts range selection

      r   reset max marker (horizontal bar resolution) for LCD value normalization

      l   linear intensity axis on LCD
      L   logarithmic intensity axis on LCD
      1    250 steps per Goertzel analysis
      2    500 steps
      3   1000 steps
      4   1250 steps
      5   1500 steps
      6   1750 steps
      7   2000 steps
      8   2250 steps
      9   2500 steps
      o   output as magnitude
      O   output as power (I2C always uses magnitude)
      ?   show help message
      h   show help message

UART Interface

115200, 8N1



      <channel>, <frequency>, <intensity>

      <channel>, <frequency>, <intensity>


I2C Interface

    I2C WRITE:

     ADR    BIN-ADR      I2C-BYTES (the "NXT-STYLE")

     0x48   0b 1001000   0x90
    (0x49   0b 1001001   0x92)
    (0x4A   0b 1001010   0x94)
    (0x4B   0b 1001011   0x96)

    | <ADR> | <CMD> |
    <ADR> = standard I2C 7 bit address + !W bit
    <CMD> = ASCII command as described in "HOTKEYS" table above

    For a write command, there is no difference between 0x48 and the other addresses.
    Just stick to the first one...

    I2C READ:

     CH   ADR    BIN-ADR      I2C-BYTES (the "NXT-STYLE")

      1   0x48   0b 1001000   0x91
      2   0x49   0b 1001001   0x93
      3   0x4A   0b 1001010   0x95
      4   0x4B   0b 1001011   0x97

    | <ADR> | <STA> | <T1H> | <T1L> | <T2H> | <T2L> |...| <T8L> |
    <ADR> = standard I2C 7 bit address + R bit
    <STA> = Raydialer status byte (not in use)
    <TnH> = tone level, high byte
    <TnL> = tone level, low  byte

    Per channel (receiver photodiode), 17 bytes are returned.
    Each high/low byte combination represents a 16bit magnitude value of a "tone".


     TONE  f[Hz]
       1    697
       2    770
       3    852
       4    941
       5   1209
       6   1336
       7   1477
       8   1633


RobotC Demo

The provided example (see download section below) does nothing else, but align the brick with three TX1-beacons.

Additionally, it balances on two wheels, but this is a different story.

That's it for now. Nothing more, nothing less...

pbLua Demo


NXC Demo


Useless Pics

minimal TX (pure analog)

minimal RX
totally saturating the receiver;
still working ;)
Well, not quite exactly...
The S817 isn't really that large ;-)
the real TX hardware
the real RX1 hardware
TX mounted on a battery pack
do NOT attach a 9V battery ;-)



- schematic (PDF)
- placement (PDF)
- layout, Eagle (BRD)
DOWNLOAD: RayDialer-TX_hard_V12.zip V1.2; all-inclusive version

DOWNLOAD: RayDialer-RX1_hard_V12.zip V1.2 HW; 12/2010
DOWNLOAD: RayDialer-RX1_firm_V11.zip V1.1 FW; 05/2012
DOWNLOAD: RayDialer-RX1_source_V11.zip V1.1 FW; 05/2012
DOWNLOAD: RayDialer-RX1_scilab-ana_V06.zip V0.6 Scilab Sweep Analyzer; 11/2010

DOWNLOAD: RayBalancerDemo_RobotC_V01.zip just a q&d RobugC example; 05/2012

ASkr 06/2010 initial version
ASkr 09/2010 found some time to add RX1 HW
ASkr 11/2010 added the missing HW TX V1.2; added FW RX1 V0.5; added HW RX1 V1.1
ASkr 12/2010 changed HW to V1.2
ASkr 11/2011 added firmware source V1.0
ASkr 05/2012 RX1 firmware V1.1 + source