IR transmitter & recorder

Hey,

I’ve been thinking that I’d like to be able to create an IR recorder and transmitter with the Spark, I had a look and can see that boards are available for the arduino for quite low cost - would they work with the Spark?

My Grandad is losing his sight & can no longer work out how to turn on his tv, switch AV to HDMI, turn on Sky & navigate to Sky Sports … It would be great if I could pre-prog the routine into the core & then have one physical button that he could press to deal with the technical bits.

That said I guess it may just be another frustration if it didn’t work consistently - I’m hoping its pretty simple though!

Thanks

1 Like

Not really Spark related, but most of the Logitech Harmony remote controls allow you to setup “single button” actions that turn on the TV + sound system + set top, pause, then send commands to navigate to a specific channel. You can even have different things like “Play Games” which turns on the PS3 + TV and changes to the right input etc.

Hey @bedsingar - that sounds like an awesome project idea. There aren't any IR shields available for the Core yet, so using an Arduino shield might be the easiest way forward. If you post the board you're looking at, I can take a look to see if it'd be compatible. If you're using an Arduino shield, you might need something like the [Shield Shield] (Particle Welcome to the Particle docs) to convert the Core to the right pinout/geometry, but it will likely be plug + play after that :smile:

I’m also interested in using the spark as an IR emitter. The Global Cache iTach Flex came out almost a year ago, I was pretty excited about the product but it was/is closed source and didn’t perform as expected.

I’ve worked with Logitech, iRule, URC, RTI, Savant, Crestron, and a slew of other publicly marketed control software, all of which are designed around proprietary software and hardware.

Using the Core would open up MANY doors to the custom control industry to individuals like myself. My core will be coming to me as part of the January shipment. I hope to start building libraries for the core as soon as I receive mine.

Would a shield be necessary if we plan to solder?

@cantrellsmedia - Nope! The Shield is only if you want plug and play kind of functionality. If you're soldering, you can build any way that fits your project specifications best. The advantages of using a Shield Shield is that it works out of the box without a soldering iron, and also includes logic level converters between 3.3V and 5V.

That’s good news. I’m pretty new to Hardware programming and development. I’m really looking forward to this project. Soon!

Well I found this tutorial which I think shows the code needed, method & how to wire up the components … I’d imagine that it would need modifying for use with the Spark core though?

I’m only planning to wire up on a breadboard to start with to see if I can get something working… have been ripping apart an old VCR & its remote today as I guess the IR parts are what I’d need to get this working - not sure if one IR bulb can work for all devices though. - I think the difference is in the pulse timings? … have some reading to do!

@Delphy thanks for the heads up I’ll look into it as a backup :slight_smile:

@will was initially looking at these bits , but have since pulled some parts out to recycle them - no idea if that will work though haha:

http://www.colorapples.com/digital-ir-receiver-module-for-arduino-p-105193.html#.Urx-bvRdUa0

@bedsingar - looks like you’ve identified some good components for your project. The Adafruit part accepts digital inputs 3V to 5V, so it’ll work great with the Core. Couldn’t find the datasheet for the banggood.com part, but it looks like it’s breadboard compatible and might work. The receiver looks like it’ll work too. All of these parts, because they are breakout modules and aren’t full shields, should work equally well with the Core as any Arduino.

Keep us updated on your progress!

You may be interested in a project funded not too long ago on Indiegogo called AnalysIR. Hope it helps!

:smile:

1 Like

Thanks everybody for your suggestions - I’ve made some progress and thought it would be good to give an update as it may be a good time to learn from others experience before I make too many more mistakes!

So I looked at the arduino code that I linked to above, but being that I’m new to this I didn’t understand how to port the libraries (.h files ?!) so that they could be included on the core. - I looked for an example but it seems the servo lib is the only one so far (other than maybe LCD) and that has been included by default. The problem here is that I can’t see where I’d put the .h file as I flash the code via the api.

Any way what I could understand was how a function could be written to turn a led on and off, how the core can be powered by AA batteries via the vin port and how a sequence of on’s and off’s could be programmed when a push button is pressed.

So I read the detail on this page: http://www.remotecentral.com/features/irdisp3.htm which explains how a hex code can be converted to a series of burst pairs. These are as I understand it essentially on and offs of the IR led for a specified length of time at a given frequency.

I took the hex code for the channel up function from here: http://www.geekzone.co.nz/forums.asp?topicid=94816

which looks like:

0000 0078 0000 0024 000E 000A 0006 0009 0005 0015 0006 000A 0006 001B 0005 0015 0005 000A 0006 000A 0006 000A 0005 0009 0006 0015 0006 000F 0006 0015 0005 000A 0006 0015 0006 000A 0005 000A 0005 0C35 000E 000A 0006 000A 0005 0015 0006 000A 0006 001B 0005 0015 0006 000A 0006 000A 0006 000A 0005 000A 0006 0015 0006 000F 0006 0015 0005 000A 0006 0015 0006 000A 0005 000A 0006 0C15 

Then used a hex to decimal converter to turn this into a sequence that could be used in the code for the core. - There maybe much more elegant ways of actually converting hex code with the core … which would be nice but I’m not that advanced yet!

http://www.binaryhexconverter.com/hex-to-decimal-converter

/*
 Button
 
 Turns on and off a light emitting diode(LED) connected to digital  
 pin 3, when pressing a pushbutton attached to pin 2. 

*/
// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  3;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int freq = 1 / 36000 ; // which gives value in milliseconds
//int freq = 10 ; // so that we can see it with the human eye for testing (via digital camera)

//functions

void IrOnOff(int x, int y)

{  
    digitalWrite(ledPin, HIGH); // turn LED on
    delay(x * freq);               // Wait for  X microseconds
    digitalWrite(ledPin, LOW); // turn LED off
    delay(y * freq);               // Wait for  Y microseconds
}

void SKYCHUP()
{

IrOnOff(14,10);
IrOnOff(6,9);
IrOnOff(5,21);
IrOnOff(6, 10);
IrOnOff(6,27);
IrOnOff(5, 21);
IrOnOff(5,10);
IrOnOff(6,10);
IrOnOff(6,10);
IrOnOff(5, 21);
IrOnOff(6,21);
IrOnOff(6,15);
IrOnOff(6,21);
IrOnOff(5,10);
IrOnOff(6,21);
IrOnOff(6,10);
IrOnOff(5,10);
IrOnOff(5,3125);
IrOnOff(14,10);
IrOnOff(6,10);
IrOnOff(5,21);
IrOnOff(6,10);
IrOnOff(6,27);
IrOnOff(5,21);
IrOnOff(6,10);
IrOnOff(6,10);
IrOnOff(6,10);
IrOnOff(5,10);
IrOnOff(6,21);
IrOnOff(6,15);
IrOnOff(6,21);
IrOnOff(5,10);
IrOnOff(6,21);
IrOnOff(6,10);
IrOnOff(5,10);
IrOnOff(6,3093);

}

//main code

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop()
{
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) 
  {     
    //IR SEQUENCE HERE
        SKYCHUP();
  } 
  else 
  {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
  }
}

Here is a link to the video so far: http://youtu.be/9HZCocjik8g … unfortunately when I changed the code back to milliseconds it didn’t actually work! - but I think this is to do with the frequency / maybe my understanding of the delay function.

So the current function is getting the delay frequency by taking 1 (second) divided by 36000 the ir frequency derived from the second word in the hex sequence - this gives a result in microseconds I think - but this could be wrong. Basically I’ve spent time here trying to prove that the hardware is working & also that the code written for the Core will conceptually work.

Now I guess more time needed on understanding the logic behind the frequency of pulses and getting one signal to actually work. Then I need to know how many of these functions can be stored in the core ?? i.e channel up channel down etc - with no external storage I presume the capacity is limited?

Also then when I do finally get this bit working & move onto the receiver, how can I monitor the output? - with a classic arduino I assume you could just plug in via usb and monitor the output on the PC? - but with the core running through the API I’m not sure how to do that - especially given that data transmitted back is limited to integers (I read somewhere on here) … lots to think about!

Any suggestions / pointers welcome!

Thanks

Nice work so far. I just received notice that my core will be shipping soon. I’ll jump on board with this project asap.

I’ll be using an Android and an iPad for my project. I think it would be best to store your IR data on your controlling device. In my case, the IR data will be stored in my app and would send the information to the core.

I certainly wouldn’t want to overlook the ability to store the IR data on the core. Doing so would give systems integrators the ability to standardize their user interfaces by having the ability to program the core specifically to the equipment it is assigned to.

Example: I used Webduino to send URL commands to my Arduino, which then turned on a relay. My URL scheme was as simple as: 192.168.1.1:8080/pinD1=0

I used this method to make an iPad control system for my jeep.

I would like to communicate using JSON and make it as simple as sending a URL that looks like this:

192.168.1.1:8080/tvOn
192.168.1.1:8080/tvOff

The core would accept this command and fire off the IR signal for the TV it is assigned to. If your client switched TVs to a different brand, the integrator could easily reprogram the core remotely.

I’ll start posting code and resources as soon as my core arrives.

3 Likes

Have you been only using the delay() function which is in milliseconds, or have you tried using the delayMicroseconds() function which is what you want most likely.

Yes, 1 / 36,000Hz = 27.7777 microseconds period.

int freq = 1 / 36000 ; // which gives value in milliseconds is no good though, because it will result in a float data type 0.00002777 that will be truncated to 0 for integer type. If you know the duration is 27.777 us, then just code a value of uint32_t pulseDuration = 27; I think you'll find with the overhead of the C code, 27us will be more like 28us or 29us anyway.

Also, digitalWrite() takes about 2 microseconds to perform... so you may want to subtract 2 from your delays for high and low.

You probably won't run into a limit of functiions... and there are many ways to condense this down once you get it working.

This is the hardest part right now. pulseIn() is not supported yet, and attachInterrupt() does not give you access to a millis() counter (which also doesn't exist yet). So your best bet might be recording the timing with an Arduino, and then getting the code working on that first for transmitting. Then porting it over to the Spark Core :spark: and finally adding your remote web interface Spark.function()'s

1 Like

Hi thanks for the advice.

I've updated the code to use delayMiscroseconds() and have switched over to using uint32_t as well.

I've now got a signal being transmitted from the ir led connected to the core which analysir can detect.

For some reason though it is very erratic. For instance if I press the CH+ button on the remote

I get a constant capture like this:

When I tried the on off sequence that I'd prepared before it was giving very inconsistent results that were nothing like the picture above.

I decided that this was maybe because the routine was only running whilst the button was pressed ... I'm not sure how to make it only run once for each press of the button at the moment.

So I switched to something simple that I was expecting to give me a straightforward and consistent pattern:

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  3;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
uint32_t freq = 27 ; // which gives pulse frequency in microseconds

//functions

void IrOnOff(int x, int y)

{
  
    digitalWrite(ledPin, HIGH); // turn LED on less
    //delayMicroseconds((x * freq) -2 );               // Wait for  X microseconds
    delayMicroseconds((x) -2 );
    digitalWrite(ledPin, LOW); // turn LED off less
    delayMicroseconds((y) -2 );
    //delayMicroseconds((y * freq)-2);               // Wait for  Y microseconds
}


void TESTSIGNAL()
{
IrOnOff(100 ,200); //1
IrOnOff(100 ,200); //2
IrOnOff(100 ,200); //3
IrOnOff(100 ,200); //4
IrOnOff(100 ,200); //5
}

//main code

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop()
{
TESTSIGNAL();
}

I.E now that the loop was constantly running and the on off durations were consistent, I expected a reasonably even graph....

I would have expected this to show the on period as half the duration of the off period which isn't what analysir is capturing. Also the on seems to drop power which I find odd. Until I can understand why this is I think it will be hard to replicate a real signal!

Also I figured as Analysir is capable of capturing the on off sequence and the durations reasonably accurately in microseconds - maybe I can do away with the freq variable as I could instead pass the actual number of microseconds duration for on and off to the function which is now using delayMicroseconds() and so should result in the correct frequency any way.

The other thing I noticed is that analysir recognises the Sky remote as an RC6 protocol and the signal from the core as RAW. Which I think is more to do with the signal being sent than the hardware, but I'm going to check that with the writers of analysir - I've found them to be quite helpful so far :slight_smile:

Indeed the current modulation frequency is 29.7 khz - which I guess will need to be compensated for unless I adopt the above approach.

Thanks

1 Like

The Jeep control looks awesome, good work. I’ve just started dabbling in VB.NET too and can see how the API calls could be integrated into a website. Personally I’d like to be able to have a configuration front end where you could select tv brand and model + other equipment. Drag on a series of commands and say which physical button they should be assigned to. Then use the API to flash the core with the updated code … not sure how easy that would be though!!

Still hoping to get the basics working first - would just like to see the channel change!!

I see what AnalisIR is, and it looks very useful! I think I may have to get a copy of that software :wink: Do they update it regularly? http://www.indiegogo.com/projects/analysir-ir-analyzer-decoder-with-arduino-raspberry-pi-and-mcu

First of all, what IR decoder are you using and what carrier frequencies will it demodulate?

You will have to figure out if the different remotes that you are trying to record and playback have different carrier frequencies as well, because you are modulating a carrier frequency with the :spark: Core If you don’t generate a carrier frequency that the demodulator you have will decode, it will look like garbage. Also, based on the current code, I can tell you that that is in fact your problem :wink:

This app note may help you understand the different IR schemes and what the signal looks like that you are trying to create:

Check out my simple ton generator for the Spark Core:
https://gist.github.com/technobly/8342067

It has the necessary frequency generation (50% duty cycle) for a duration that you need for IR stuff. I’m also using direct port manipulation so there is no 2us delay like when using digitalWrite();

If you’re not stuck on Spark, and are willing to use a windows or linux box, you might want to check out the USB Infrared Toy, which is a piece of bare electronics (like the Spark) that can send/receive IR signals. It’s controlled via USB, and so won’t work with the Spark.

Here’s a nice code snippet to play with. I just dialed this in with my oscilloscope, so the timing is good!

You still have to emulate the correct bit pattern, and start bit patterns, etc…

uint16_t IR_PIN = D6;
uint16_t x;
 
void setup() {
  pinMode(IR_PIN,OUTPUT);
}
 
void loop() {
  // Output 10 bits, 10ms on, 20ms off.
  for(x=0;x<10;x++) {
    // Output Pin, Carrier Frequency (Hz), Duration ON (ms), Duration OFF (ms)
    IRsendOnOff(IR_PIN, 36000, 10, 20);
  }
  // Output 10 bits, 10ms off, 40ms on.
  for(x=0;x<10;x++) {
    // Output Pin, Carrier Frequency (Hz), Duration ON (ms), Duration OFF (ms)
    IRsendOffOn(IR_PIN, 36000, 10, 40);
  }
  delay(1000);
}

void IRsendOnOff(uint16_t pin, uint32_t carrierFreq, uint16_t durationOn, uint16_t durationOff) {
  uint32_t half_period_us = (uint32_t)(500000/carrierFreq); // (1/carrierFreq/2*1000000);
  // On Duration - output carrier frequency for durationOn (ms)
  for(uint32_t x=0;x<(uint32_t)(durationOn*carrierFreq/1000);x++) {
    PIN_MAP[pin].gpio_peripheral->BSRR = PIN_MAP[pin].gpio_pin; // HIGH
    delayMicroseconds(half_period_us);
    PIN_MAP[pin].gpio_peripheral->BRR = PIN_MAP[pin].gpio_pin;  // LOW
    delayMicroseconds(half_period_us);
  }
  // Off Duration - output nothing for durationOff(ms)
  delay(durationOff);
}

void IRsendOffOn(uint16_t pin, uint32_t carrierFreq, uint16_t durationOn, uint16_t durationOff) {
  uint32_t half_period_us = (uint32_t)(500000/carrierFreq); // (1/carrierFreq/2*1000000);
  // On Duration - output nothing for durationOn(ms)
  delay(durationOn);
  // Off Duration - output carrier frequency for durationOff (ms)
  for(uint32_t x=0;x<(uint32_t)(durationOff*carrierFreq/1000);x++) {
    PIN_MAP[pin].gpio_peripheral->BSRR = PIN_MAP[pin].gpio_pin; // HIGH
    delayMicroseconds(half_period_us);
    PIN_MAP[pin].gpio_peripheral->BRR = PIN_MAP[pin].gpio_pin;  // LOW
    delayMicroseconds(half_period_us);
  }
}

Let’s see how your AnalysIR works with this code.

1 Like

HI Guys - great to see the efforts being made with the spark core.
Here are some initial comments for you:

  • The best way to get the modulation frequency is to to use PWM and then just turn the PWM on and off to match the marks/spaces. Unfortunately, we are not familiar with the Spark Core yet so can’t help there. Normally there is a PWM facility that just requires some register configuration depending on the clock/timer & pin used.

  • I would suggest a duty cycle of circa 33% for IR modulation.

  • If you are generating the modulation in code loops, you have to decrease the delay for the half period to allow for the code/loop overhead. I know on a 16MHz Arduino I had to decrease the half-period by 6 uSecs or so to get it accurate.

  • In general, use delayMicroseconds (vs delay) for IR, if the implementation of these functions is anything like the Arduino. Actually, I would use elapsed uSecs in preference to the delay functions, which avoids any potential limitations of the delayMicroseconds function implementation ( in the Arduino core).

  • The SKY remote is an RC6 variant with more bits(24) than the standard RC6(of 20). The marks/spaces are 444 uSecs so you will see timings of 444, 888 etc within a signal. There is also a toggle bit which is twice the duration of standard bits (and may be in a different position from the standard - I need to confirm that). The lead-in Header is 2,666 uSecs and the Header spaces 888. See this site for an explanation of standard RC6.

  • Keep all your timings to variants of the above for TX when testing, but remember that IR receivers distort the timings on reception by +/- 50->100 uSecs. (Marks can be longer and spaces can be shorter (or vice-versa?). Different models/makes of IR receivers will have different characteristics of distortion. Decoding schemes are very tolerant to cater for this.

1 Like

I am also interested in a project like this - I would like some small box that sits in my lounge within IR LED view of my air-conditioner, fan, TV and set-top box so it can transmit IR codes to control them all from an app on my Android phone. Ideally it would be a small battery operated unit so I can optimize position without having to look at ugly wires. Would be helpful if there was some chip that could learn, store & play IR codes that you teach it from the remotes for the devices.

I have a Logitech Harmony but I don’t like the way it is not really device-centric. I would rather have something that uses a better interface, preferably one that I wrote myself.