Infra red (IR) communication between objects

Hi. I'm working on a project where I have a number of objects that physically change shape depending on how a person arranges them. I'm using infra red (IR) to send messages between the objects e.g. if the correct sides are facing each other, if one object sees another etc.

I've taken Walter Anderson's code that detects IR signals (see below), which works fine when you press some buttons on a universal TV remote control). But I have two problems:

  • I don't know how to get it to differentiate between different signals. I tried comparing the value of change_count when Bit stream detected! is true, but I keep getting the same combination of "1" and "0".
  • When I try sending IR signals with this other piece of code I found (also see below), the IR detection only seems to pick it up some of the time. I've tried to figure out why this happens, and my best guess is that it has to do with the modulation at which I'm sending my custom messages. So, what do I need to modify in my IR transmission code so that the IR detection code picks it up every time?

Walter Anderson's IR detection code:

/*
 *  File....... IRanalyzer.pde 
 *  Purpose.... Records up to 128 signal changes
 *  Author..... Walter Anderson 
 *  E-mail..... wandrson@walteranderson.us 
 *  Started.... 18 May 2007 
 *  Updated.... 18 May 2007 
 * 
 *
 */ 
#include <avr/interrupt.h>
#include <avr/io.h>


#define TIMER_RESET  TCNT1 = 0
#define SAMPLE_SIZE  64

int IRpin = 2;
unsigned int TimerValue[SAMPLE_SIZE];
char direction[SAMPLE_SIZE];
byte change_count;
long time;

void setup() {
  Serial.begin(115200);
  Serial.println("Analyze IR Remote");
  TCCR1A = 0x00;          // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled
  // ICNC1=0 => Capture Noise Canceler disabled -- ICES1=0 => Input Capture Edge Select (not used) -- CTC1=0 => Clear Timer/Counter 1 on Compare/Match
  // CS12=0 CS11=1 CS10=1 => Set prescaler to clock/64
  TCCR1B = 0x03;          // 16MHz clock with prescaler means TCNT1 increments every 4uS
  // ICIE1=0 => Timer/Counter 1, Input Capture Interrupt Enable -- OCIE1A=0 => Output Compare A Match Interrupt Enable -- OCIE1B=0 => Output Compare B Match Interrupt Enable
  // TOIE1=0 => Timer 1 Overflow Interrupt Enable
  TIMSK1 = 0x00;          
  pinMode(IRpin, INPUT);
}

void loop()
{
  Serial.println("Waiting...");
  change_count = 0;
  while(digitalRead(IRpin) == HIGH) {}                                 
  TIMER_RESET;
  TimerValue[change_count] = TCNT1;
  direction[change_count++] = '0';
  while (change_count < SAMPLE_SIZE) {
    if (direction[change_count-1] == '0') {
      while(digitalRead(IRpin) == LOW) {}
      TimerValue[change_count] = TCNT1;
      direction[change_count++] = '1';
    } else {
      while(digitalRead(IRpin) == HIGH) {}
      TimerValue[change_count] = TCNT1;
      direction[change_count++] = '0';
    }
  }
  Serial.println("Bit stream detected!");
  change_count = 0;
  time = (long) TimerValue[change_count] * 4;
  Serial.print(time);
  Serial.print("\t");
  Serial.println(direction[change_count++]);
  while (change_count < SAMPLE_SIZE) {
    time = (long) TimerValue[change_count] * 4;
    Serial.print(time);
    Serial.print("\t");
    Serial.println(direction[change_count-1]);
    Serial.print(time);
    Serial.print("\t");
    Serial.println(direction[change_count++]);    
  }
  Serial.println("Bit stream end!");
  delay(2000);
}

Code that sends custom IR signals:

/* Control a Lutron Maestro light dimmer */
#define BIT_IS_SET(i, bits)  (1 << i & bits)

// LED connected to digital pin 9
const int LED_PIN = 9;
// Width of a pulse, in microseconds
const int PULSE_WIDTH = 2300;
// # of bytes per command
const int COMMAND_LENGTH = 4;    

const int FORWARD[] = {130};

const int UP[]     = {255, 136, 130, 34};
const int DOWN[]   = {255, 136, 130, 20};
const int ON[]     = {255, 136, 132, 184};
const int OFF[]    = {255, 136, 189, 18};
const int RECALL[] = {255, 136, 132, 183};

void setup()
{
  pinMode(LED_PIN, OUTPUT);
}

/* Modulate pin at 38 kHz for give number of microseconds */
void on(int pin, int time) {
  static const int period = 25;
  // found wait_time by measuring with oscilloscope
  static const int wait_time = 9;  

  for (time = time/period; time > 0; time--) {
    digitalWrite(pin, HIGH);
    delayMicroseconds(wait_time);
    digitalWrite(pin, LOW);
    delayMicroseconds(wait_time);
  }
}

/* Leave pin off for time (given in microseconds) */
void off(int pin, int time) {
  digitalWrite(pin, LOW);
  delayMicroseconds(time);
}

/* Send a byte over the IR LED */
void send_byte(int bits) {
  for (int i = 7; i >= 0; i--)
  {
    if (BIT_IS_SET(i, bits)) {
      on(LED_PIN, PULSE_WIDTH);
    } else {
      off(LED_PIN, PULSE_WIDTH);
    }
  }
}

/* Send a full command */
void command(const int bytes[]) {
  for (int i = 0; i < COMMAND_LENGTH; i++) {
    send_byte(bytes[i]);
  }
  off(LED_PIN, 4 * PULSE_WIDTH);
}

void loop()
{
  command(FORWARD);
  delay(1000);
}

You need to say what sort of hardware you are using to detect and generate the IR.
there are two sorts of IR, modulated which is what the TV remotes use and un modulated which is (generally) what breaking beams use.

In this context you need to use a modulated beam so your objects need to emulate both the transmission and reception of TV like messages. You need a modulated receiver module to detect this as a straight IR photo transistor won''t do.

Then (and this is the hard part) you need to arrange a software protocol that arranges when to send and when to receive. Finally you need to work out what messages to send and what they mean.

Well, I'm using a pair of infrared emitters & detectors, the ones that you can get off Sparkfun (Infrared Emitters and Detectors - SEN-00241 - SparkFun Electronics) and connecting them to my Arduino Deumilanove. I'm hooking them up the same way as jerrya.net didfor his camera shutter test (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1233960430/).

You need a modulated receiver module to detect this as a straight IR photo transistor won''t do.

So, does that mean these IR detectors probably aren't the ones I need? (Sorry, I've used IR before but not to send specific messages).

Then (and this is the hard part) you need to arrange a software protocol that arranges when to send and when to receive.

Would you happen to know of an example I could look at/work from?

Finally you need to work out what messages to send and what they mean.

Well, I just want to be able to send different messages for the different sides of my object e.g. "top", "bottom" "side 1" etc... From what I understand, all I would need to do is change how I modulate the IR beam?