Go Down

Topic: Lego powerfunctions IR (Read 5 times) previous topic - next topic

SuperCow

Nov 26, 2008, 11:23 pm Last Edit: Nov 26, 2008, 11:27 pm by SuperCow Reason: 1
Ive had a idea to use a irduino as a IR transmitter to control the lego powerfunction receiver.

But I am a total nooby in this, ive done some research and found the protocol document for the lego transmitter:
http://www.philohome.com/pf/LEGO_Power_Functions_RC.pdf

And here is some example code of someone who made his lego RCX brick to do what i want with the arduino:
http://www.fial.com/bob/lego/PowerFunctions.zip

You can do more things then the lego transmitter, like PWM!

Can someone help me out, or put me one the right track so i can make it?

SuperCow

#1
Nov 27, 2008, 11:01 pm Last Edit: Nov 27, 2008, 11:19 pm by SuperCow Reason: 1
Ive made some starting code, but its not working.
I used most of the code from the RCX brick because its also C code

Code: [Select]
//mode
#define COMBO_DIRECT_MODE 0x01
#define SINGLE_PIN_CONTINUOUS 0x2
#define SINGLE_PIN_TIMEOUT 0x3
#define SINGLE_OUTPUT 0x4

//PWM speed steps
#define PWM_FLT 0x0
#define PWM_FWD1 0x1
#define PWM_FWD2 0x2
#define PWM_FWD3 0x3
#define PWM_FWD4 0x4
#define PWM_FWD5 0x5
#define PWM_FWD6 0x6
#define PWM_FWD7 0x7
#define PWM_BRK 0x8
#define PWM_REV7 0x9
#define PWM_REV6 0xA
#define PWM_REV5 0xB
#define PWM_REV4 0xC
#define PWM_REV3 0xD
#define PWM_REV2 0xE
#define PWM_REV1 0xf

//channel
#define CH1 0x0
#define CH2 0x1
#define CH3 0x2
#define CH4 0x3

//output
#define RED 0x0
#define BLUE 0x1

int IRPin = 13;
int toggle[4] = {0,0,0,0};

void setup()
{
 pinMode(IRPin, OUTPUT);
 //Serial.begin(9600);
 //delay(2);
 
}

void loop()
{
 SingleOutput(PWM_FWD7, RED, CH1);
 //delay(2000);
 
}

void pf_send(int code1, int code2)
{
 int x = 128;
 
 start_stop_bit();
 
 while (x)
 {
   digitalWrite(IRPin, HIGH);
   tx_pause();
   digitalWrite(IRPin, LOW);
   
   if (code1 & x) //high bit
     high_pause();
   else //low bit
     low_pause();
   
   x >>= 1;  //next bit
 }
 
 x = 128;
 while (x)
 {
   digitalWrite(IRPin, HIGH);
   tx_pause();
   digitalWrite(IRPin, LOW);
   
   if (code2 & x) // high bit
     high_pause();
   else //low bit
     low_pause();

   x >>= 1;  //next bit
 }
 delay(10);
}

void SingleOutput(int pwm, int output, int channel)
{
  int nib1, nib2, nib3, nib4, i;

  //set nibs
  nib1 = toggle[channel] | channel;
  nib2 = SINGLE_OUTPUT | output;
  nib3 = pwm;
  nib4 = 0xf ^ nib1 ^ nib2 ^ nib3;
 
  for(i = 0; i < 6; i++)
  {
    message_pause(channel, i);
    pf_send(nib1 << 4 | nib2, nib3 << 4 | nib4);    
  }
 
  if(toggle[channel] == 0)
    toggle[channel] = 8;
  else
    toggle[channel] = 0;
}

void start_pause()
{
 delayMicroseconds(1014);
}

void high_pause()
{
 delayMicroseconds(546);
}

void low_pause()
{
 delayMicroseconds(260);
}

void tx_pause()
{
 delayMicroseconds(156);
}

void message_pause(int channel, int count)
{
 unsigned char a = 0;
 
 if(count == 0)
   a = 4 - channel + 1;
 else if(count == 1 || count == 2)
   a = 5;
 else if(count == 3 || count == 4)
   a = 5 + (channel + 1) * 2;
     
 delayMicroseconds(a * 77);
}


void start_stop_bit()
{
digitalWrite(IRPin, HIGH);
tx_pause();
digitalWrite(IRPin, LOW);
start_pause();
}



The RCX code used some sort of for loop delay, i use delayMicroseconds.

Can this be the problem?
Can someone help me?

SuperCow

Oke Ive got it working now!!!

IR need to pulse ofcourse, so i used David Cuartielles code of the remote control the oscillationWrite() function to make a pulse.

Now it works like a charm, the code is not done yet, but if you put this on your arduino with a ir led on port 13 your lego 8275 bulldozer wil drive forward on a interval of 2 secs

Not bad for me *couch* first time i play with arduino.

Code: [Select]
//mode
#define COMBO_DIRECT_MODE 0x01
#define SINGLE_PIN_CONTINUOUS 0x2
#define SINGLE_PIN_TIMEOUT 0x3
#define SINGLE_OUTPUT 0x4

//PWM speed steps
#define PWM_FLT 0x0
#define PWM_FWD1 0x1
#define PWM_FWD2 0x2
#define PWM_FWD3 0x3
#define PWM_FWD4 0x4
#define PWM_FWD5 0x5
#define PWM_FWD6 0x6
#define PWM_FWD7 0x7
#define PWM_BRK 0x8
#define PWM_REV7 0x9
#define PWM_REV6 0xA
#define PWM_REV5 0xB
#define PWM_REV4 0xC
#define PWM_REV3 0xD
#define PWM_REV2 0xE
#define PWM_REV1 0xf

//speed
#define RED_FLT 0x0
#define RED_FWD 0x1
#define RED_REV 0x2
#define RED_BRK 0x3
#define BLUE_FLT 0x0
#define BLUE_FWD 0x4
#define BLUE_REV 0x8
#define BLUE_BRK 0xC


//channel
#define CH1 0x0
#define CH2 0x1
#define CH3 0x2
#define CH4 0x3

//output
#define RED 0x0
#define BLUE 0x1

int IRPin = 13;
int toggle[4] = {0,0,0,0};

void setup()
{
 pinMode(IRPin, OUTPUT);
 digitalWrite(IRPin, LOW);
 //Serial.begin(9600);
 //delay(2);
 
}

void loop()
{
 ComboMode(BLUE_REV, RED_FWD, CH1);
 delay(2000);
 
}

void pf_send(int code1, int code2)
{
 int x = 128;
 
 start_stop_bit();
 
 while (x)
 {
   oscillationWrite(IRPin, 156);
   
   if (code1 & x) //high bit
     high_pause();
   else //low bit
     low_pause();
   
   x >>= 1;  //next bit
 }
 
 x = 128;
 while (x)
 {
   oscillationWrite(IRPin, 156);
   
   if (code2 & x) // high bit
     high_pause();
   else //low bit
     low_pause();

   x >>= 1;  //next bit
 }
 
 start_stop_bit();
 delay(10);
}

void ComboMode(int blue_speed, int red_speed, int channel)
{
 int nib1, nib2, nib3, nib4, i;
 
 //set nibs
 nib1 = channel;
 nib2 = COMBO_DIRECT_MODE;
 nib3 = blue_speed | red_speed;
 nib4 = 0xf ^ nib1 ^ nib2 ^ nib3;

 for(i = 0; i < 6; i++)
 {
   message_pause(channel, i);
   pf_send(nib1 << 4 | nib2, nib3 << 4 | nib4);    
 }
}


void SingleOutput(int pwm, int output, int channel)
{
  int nib1, nib2, nib3, nib4, i;

  //set nibs
  nib1 = toggle[channel] | channel;
  nib2 = SINGLE_OUTPUT | output;
  nib3 = pwm;
  nib4 = 0xf ^ nib1 ^ nib2 ^ nib3;
 
  for(i = 0; i < 6; i++)
  {
    message_pause(channel, i);
    pf_send(nib1 << 4 | nib2, nib3 << 4 | nib4);    
  }
 
  if(toggle[channel] == 0)
    toggle[channel] = 8;
  else
    toggle[channel] = 0;
}

void start_pause()
{
 delayMicroseconds(1014);
}

void high_pause()
{
 delayMicroseconds(546);
}

void low_pause()
{
 delayMicroseconds(260);
}

void tx_pause()
{
 delayMicroseconds(156);
}

void message_pause(int channel, int count)
{
 unsigned char a = 0;
 
 if(count == 0)
   a = 4 - channel + 1;
 else if(count == 1 || count == 2)
   a = 5;
 else if(count == 3 || count == 4)
   a = 5 + (channel + 1) * 2;
     
 delayMicroseconds(a * 77);
}


void start_stop_bit()
{
 oscillationWrite(IRPin, 156);  
 //digitalWrite(IRPin, HIGH);
 //tx_pause();
 //digitalWrite(IRPin, LOW);
 start_pause();
}

void oscillationWrite(int pin, int time) {
 for(int i = 0; i <= time/26; i++) {
   digitalWrite(pin, HIGH);
   delayMicroseconds(13);
   digitalWrite(pin, LOW);
   delayMicroseconds(13);
 }
}

SuperCow

Oke,  ive got the code fully working now, and i made a java program to control it.



Power is ofcourse to switch it on (maybe wait a few sec till the arduino is done booting)
channel selector;
2 throttle sliders, and you can link them;
checkbox below is to turn Forward<-> backwards

arduino code: http://www.rjw.speedxs.nl/arduino/lego_ir.pde

java program: http://www.rjw.speedxs.nl/arduino/Lego Powerfunctions.rar atmthe Java program is hardcoded to COM4.

vanakaru

I would like to try this code of yours. Could you fix the dead links or email me at erikik at hot dot ee

mrfriss

Yes, please share the code!

Go Up