mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Simple Infra-Red record/playback

Wed Nov 25, 2015 9:17 am

I've successfully managed to get LIRC setup on my Pi but its a lot of faffing about to just simply record an IR remote key-press and then replay it on demand.

Has anyone done anything simpler than LIRC on their Pi?
Or come up with simple prog?


Preferably in Python :)

Matthew

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Nov 25, 2015 10:05 am

That may be feasible now without a great deal of effort.

viewtopic.php?p=745189#p745189

Should allow you to capture the waveform.

The playback will not have the 38kHz (or so) modulation needed but I think that could be added using the wave chain features I have since added to pigpio.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Thu Dec 10, 2015 9:42 pm

Thanks Joan

Really want to run one prog to do the recording - stick result in a file

Then have the main TX prog for sending that can read the file.

I can see that the 38Khz modulation is the main barrier - maybe I should try using a hardware 38Khz keyed oscilator.

Maybe a 555 with a gated output controlled by a pin?

Matthew

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Thu Dec 10, 2015 9:54 pm

I keep meaning to write a program for this. Probably about time I started. I'll knock something simple together over the week end.

The IR modulation is not a problem any more.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Thu Dec 10, 2015 10:23 pm

I keep meaning to write a program for this. Probably about time I started. I'll knock something simple together over the week end.
Very kind of you :)

Just a little note - I've only used the RPi.GPIO python lib in my projects before - can I install yours as well and use it at same time, with RPi.GPIO doing simple stuff on other pins and just using yours for clever IR ?

Matthew

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Mon Dec 14, 2015 10:51 am

Generally pigpio plays nicely with the other libraries.

Normally nothing needs to be done unless you are using another DMA based utility (e.g. servoblaster). For DMA based utility you need to ensure pigpio and the utility are using different DMA channels (e.g. by using the pigpio daemon's -d or -e options).

Here is some Python to record and playback IR codes. It is work in progress but it works to switch my TV channels.
irrp_py.png
irrp_py.png (40.51 KiB) Viewed 8465 times
Source at http://abyz.co.uk/rpi/pigpio/examples.h ... on_irrp_py

Code: Select all

#!/usr/bin/env python

# irrp.py
# 2015-12-13
# Public Domain

import time
import json
import os
import argparse

import pigpio

parser = argparse.ArgumentParser()

group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-r", "--record", help="record IR codes", action="store_true")
group.add_argument("-p", "--play", help="play IR codes", action="store_true")
group.add_argument("-t", "--tidy", help="tidy data", action="store_true")

parser.add_argument("-g", "--gpio", help="GPIO", type=int, required=True)

parser.add_argument("-f", "--file", help="Filename", required=True)

parser.add_argument('id', nargs='+', type=str, help='IR codes')

parser.add_argument("--pre",    help="preamble millis",  type=int, default=20)
parser.add_argument("--post",   help="postamble millis", type=int, default=20)
parser.add_argument("--glitch", help="glitch micros", type=int,   default=100)
parser.add_argument("--freq",   help="frequency kHz", type=float, default=38.0)

parser.add_argument("-v", "--verbose", help="Be verbose", action="store_true")

args = parser.parse_args()

GPIO = args.gpio
FILE = args.file
GLIT = args.glitch
PRE  = args.pre
POST = args.post
FREQ = args.freq
VERB = args.verbose

PRE_US = PRE * 1000

last_tick = None
in_code = False
code = []
code_done = False

def backup(f):
   try:
      os.rename(os.path.realpath(f)+".bak1", os.path.realpath(f)+".bak2")
   except:
      pass

   try:
      os.rename(os.path.realpath(f)+".bak", os.path.realpath(f)+".bak1")
   except:
      pass

   try:
      os.rename(os.path.realpath(f), os.path.realpath(f)+".bak")
   except:
      pass

def carrier(gpio, frequency, micros, dutycycle=0.5):
   """
   Generate cycles of carrier on gpio with frequency and dutycycle.
   """
   wf = []
   cycle = 1000.0 / frequency
   cycles = int(round(micros/cycle))
   on = int(round(cycle * dutycycle))
   sofar = 0
   for c in range(cycles):
      target = int(round((c+1)*cycle))
      sofar += on
      off = target - sofar
      sofar += off
      wf.append(pigpio.pulse(1<<gpio, 0, on))
      wf.append(pigpio.pulse(0, 1<<gpio, off))
   return wf

def compare(p1, p2):
   if len(p1) != len(p2):
      return False
   for i in range(len(p1)):
      v = p1[i] / p2[i]
      if (v < 0.8) or (v > 1.2):
         return False
   for i in range(len(p1)):
       p1[i] = int(round((p1[i]+p2[i])/2.0))
   return True

def normalise(c):
   entries = len(c)
   p = [0]*entries # Set all entries not processed.
   for i in range(entries):
      if not p[i]: # Not processed?
         v = c[i]
         tot = v
         similar = 1.0
         for j in range(i+2, entries, 2): # Find unprocessed similar.
            if not p[j]: # Unprocessed.
               if c[j]*0.8 < v < c[j]*1.2: # Similar.
                  tot = tot + c[j]
                  similar += 1.0
         newv = tot / similar
         c[i] = newv
         for j in range(i+2, entries, 2): # Normalise similar.
            if not p[j]: # Unprocessed.
               if c[j]*0.8 < v < c[j]*1.2: # Similar.
                  c[j] = newv
                  p[j] = 1

def end_of_code():
   global code, code_done
   if len(code) > 10:
      normalise(code)
      code_done = True
   else:
      code = []
      print("Short code, probably a repeat, try again")


def cbf(gpio, level, tick):
   global last_tick, in_code, code, code_done
   if last_tick is not None:
      if level != pigpio.TIMEOUT:
         edge = pigpio.tickDiff(last_tick, tick)
         if edge > PRE_US: # Start or stop of a code.
            if in_code:
               in_code = False
               pi.set_watchdog(GPIO, 0) # Cancel watchdog.
               end_of_code()
            else:
               if not code_done:
                  in_code = True
                  pi.set_watchdog(GPIO, POST) # Start watchdog.
         else:
            if in_code:
               code.append(edge)
      else: # Timeout.
         pi.set_watchdog(GPIO, 0) # Cancel watchdog.
         if in_code:
            in_code = False
            end_of_code()
   if level != pigpio.TIMEOUT:
      last_tick = tick

pi = pigpio.pi() # Connect to Pi.

if args.record: # Record.

   try:
      f = open(FILE, "r")
      records = json.load(f)
      f.close()
   except:
      records = {}

   pi.set_mode(GPIO, pigpio.INPUT) # IR RX connected to this GPIO.
   pi.set_glitch_filter(GPIO, GLIT) # Ignore glitches.

   cb = pi.callback(GPIO, pigpio.EITHER_EDGE, cbf)

   # Process each id

   print("Recording")
   for arg in args.id:
      code = []
      code_done = False
      print("Press key for '{}'".format(arg))
      while not code_done:
         time.sleep(0.1)
      press_1 = code[:]
      match = False
      while not match:
         code = []
         code_done = False
         print("Press key for '{}' to confirm".format(arg))
         while not code_done:
            time.sleep(0.1)
         press_2 = code[:]
         the_same = compare(press_1, press_2)
         if the_same:
            match = True
            records[arg] = press_1

   backup(FILE)

   f = open(FILE, "w")
   f.write(json.dumps(records, sort_keys=True))
   f.close()

elif args.play: # Playback.

   try:
      f = open(FILE, "r")
   except:
      print("Can't open: {}".format(FILE))
      exit(0)

   records = json.load(f)

   f.close()

   pi.set_mode(GPIO, pigpio.OUTPUT) # IR TX connected to this GPIO.

   pi.wave_add_new()

   print("Playing")
   for arg in args.id:
      if arg in records:
         code = records[arg]

         # Check marks
         marks = {}
         for i in range(0, len(code), 2):
            if code[i] not in marks:
               marks[code[i]] = -1

         for i in marks:
            wf = carrier(GPIO, FREQ, i)
            pi.wave_add_generic(wf)
            wid = pi.wave_create()
            marks[i] = wid

         # Check spaces
         spaces = {}
         for i in range(1, len(code), 2):
            if code[i] not in spaces:
               spaces[code[i]] = -1

         for i in spaces:
            pi.wave_add_generic([pigpio.pulse(0, 0, i)])
            wid = pi.wave_create()
            spaces[i] = wid

         # Create wave
         wave = [0]*len(code)
         for i in range(0, len(code)):
            if i & 1: # Space
               wave[i] = spaces[code[i]]
            else: # Mark
               wave[i] = marks[code[i]]

         pi.wave_chain(wave)

         print("key "+arg)

         while pi.wave_tx_busy():
            time.sleep(0.05)

         for i in marks:
            pi.wave_delete(marks[i])
         for i in spaces:
            pi.wave_delete(spaces[i])
      else:
         print("Id {} not found".format(arg))

elif args.tidy: # Tidy data

   try:
      f = open(FILE, "r")
   except:
      print("Can't open: {}".format(FILE))
      exit(0)

   records = json.load(f)

   f.close()

   backup(FILE)

   f = open(FILE, "w")
   f.write(json.dumps(records, sort_keys=True))
   f.close()

pi.stop() # Disconnect from Pi.
To use you need an IR receiver and an IR transmitter.

sudo pigpiod # if the daemon is not running

To record, e.g.

./irrp.py -g24 -r -f ir-sat 1 2 3 4 5 6 7 8 9 0

where
-g is the Broadcom IR RX GPIO
-r is record
-f ir-sat is the file to store the codes

the other arguments are a list of the keys to record.

Code: Select all

dick ~ $ /code/irrp.py -g24 -r -f ir-sat 1 2 3 4 5 6 7 8 9 0
Recording
Press key for '1'
Short code, probably a repeat, try again
Short code, probably a repeat, try again
Press key for '1' to confirm
Short code, probably a repeat, try again
Press key for '2'
Short code, probably a repeat, try again
Press key for '2' to confirm
Press key for '3'
Short code, probably a repeat, try again
Press key for '3' to confirm
Press key for '4'
Press key for '4' to confirm
Press key for '5'
Short code, probably a repeat, try again
Press key for '5' to confirm
Short code, probably a repeat, try again
Press key for '6'
Press key for '6' to confirm
Short code, probably a repeat, try again
Short code, probably a repeat, try again
Press key for '7'
Press key for '7' to confirm
Press key for '8'
Press key for '8' to confirm
Press key for '9'
Press key for '9' to confirm
Press key for '0'
Press key for '0' to confirm
To play, e.g.
./irrp.py -g17 -p -f ir-sat 1 3

where
-g is the Broadcom IR TX GPIO
-p is play
-f ir-sat is the file of stored codes

Code: Select all

dick ~ $ /code/irrp.py -g17 -p -f ir-sat 1 3
Playing
key 1
key 3
There are a few options

Code: Select all

/code/irrp.py -h
usage: irrp.py [-h] (-r | -p | -t) -g GPIO -f FILE [--pre PRE] [--post POST]
               [--glitch GLITCH] [--freq FREQ] [-v]
               id [id ...]

positional arguments:
  id                    IR codes

optional arguments:
  -h, --help            show this help message and exit
  -r, --record          record IR codes
  -p, --play            play IR codes
  -t, --tidy            tidy data
  -g GPIO, --gpio GPIO  GPIO
  -f FILE, --file FILE  Filename
  --pre PRE             preamble millis
  --post POST           postamble millis
  --glitch GLITCH       glitch micros
  --freq FREQ           frequency kHz
  -v, --verbose         Be verbose
Tidy and verbose are not currently implemented.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Mon Jan 18, 2016 8:50 pm

1. Sorry for not getting to try this out until now

2. Its works beautifully on my PiZero :)

Thanks very much for coding this up :)
Matthew

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Mon Jan 18, 2016 8:57 pm

mattmiller wrote:1. Sorry for not getting to try this out until now

2. Its works beautifully on my PiZero :)

Thanks very much for coding this up :)
Matthew
Good to know.

I should point out that the options ended up slightly different to the ones I mentioned above. The current options are documented in the script.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Mon Jan 18, 2016 9:26 pm

A question - once I've installed pigpio - can I simply copy the folder to another machine and use it or would I have to go thru the make/install again?

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Mon Jan 18, 2016 9:32 pm

mattmiller wrote:A question - once I've installed pigpio - can I simply copy the folder to another machine and use it or would I have to go thru the make/install again?
You'd have to sudo make install again in the copied directory so all the files are copied to the appropriate place on the new machine (e.g. /usr/local/bin, /usr/local/lib, /use/local/man etc.).


mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 2:20 pm

Hi Joan
I've been spending quite some time on an IR transcoder project and I've come across a small issue
To be clear, I don't know whether its affecting the outcome of my project due to all the other issue of trying to transcode from one IR signal to another but I'd like to understand/report a big what's going on

I've got LIRC installed as well as your irrp.

I noticed that a Samsung remote menu command I was sending gets reported with a 10% different timing difference when I was switching between using LIRC to send a code from one pi to another or using irpy to send it.

I was using LIRCs irw to view both transmissions and this is a typical reading

Code: Select all

1st attempt sent using irrp 
pulse 5594
space 5036
pulse 646
space 1931
...
space 1944
pulse 620



1st attempt sent using lirc 
pulse 4655
space 4385
pulse 650
space 1598
..
space 1647
pulse 597
To make sure it wasn't irw - I installed your PiScope (lovely piece of software BTW) and recorded the received signal
1:using irpy
irrp.PNG
irrp.PNG (20.67 KiB) Viewed 8108 times
2:using LIRC
lirc.PNG
lirc.PNG (22.72 KiB) Viewed 8108 times
3:The actual samsung remote
sam.PNG
sam.PNG (30.74 KiB) Viewed 8108 times
As you can see, the LIRC and actual Samsumg remote are pretty similar but the irrp transmission seems to be streched out a bit
Now, from what I google, 10% is within margins of acceptable error in terms of IR but I thought it was an anomaly worth bringing to your attention


The LIRC file I used is

Code: Select all

         name KEY_MENU
             4560    4451     612    1632     607    1632
              607    1636     607     510     612     509
              612     510     611     510     607     514
              608    1635     608    1632     607    1632
              608     514     609     513     633     484
              612     520     597     515     607     515
              607    1632     632     489     634    1605
              611    1632     633     489     607     509
              613     516     601    1632     612     510
              611    1633     607     510     611     510
              612    1632     633    1606     632    1607
              611
and I manually made the irrp file to have the save timing

Code: Select all

{"menu": [4560, 4451, 612, 1632, 607,1632,  607,1636, 607, 510, 612, 509,  612, 510, 611, 510, 607, 514,  608,1635, 608,1632, 607,1632,  608, 514, 609, 513, 633, 484,  612, 520, 597, 515, 607, 515,  607,1632, 632, 489, 634,1605,  611,1632, 633, 489, 607, 509,  613, 516, 601,1632, 612, 510,  611,1633, 607, 510, 611, 510,  612,1632, 633,1606, 632,1607,  611]}
Matthew

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 2:43 pm

I'd have to look at the code to see if anything odd is happening.

IR remotes typically only generate a few different pulse lengths. There are a couple of different length long ones at the start for a preamble and maybe a long one at the end for a postamble. The bulk of the data is transmitted using two or three different pulse lengths.

The irrp code normalises the pulse length. It recognises the different pulses which should actually be the same in length and forms an arithmetic average. Then all pulses which should be that length are set to that one value.

By manually editing the data file and putting in pulses with many different lengths you will be stressing the software. Rather than having to generate one waveform and repeat it as needed it will have to generate many different waveforms which might introduce the delay you see (or again it might not, I haven't had a look at the code again yet).

You could try manually normalising the lengths, which is remarkably easy for a human, and a bit of a bind to do in software.

E.g.

Code: Select all

{"menu": [4560, 4451, 610, 1632, 610,1632,  610,1632, 610, 510, 610, 510,  610, 510, 610, 510, 610, 510,  610,1632, 610,1632, 610,1632,  610, 510, 610, 510, 610, 510,  610, 510, 610, 510, 610, 510,  610,1632, 610, 510, 610,1632,  610,1632, 610, 510, 610, 510,  610, 510, 610,1632, 610, 510,  610,1632, 610, 510, 610, 510,  610,1632, 610,1632, 610,1632,  610]}

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 7:29 pm

I noticed the behaviour using the standard irpy file produced by recording the samsung remote :)

I only switched to the non-standard file to compare like with like against the LIRC file

using the irrp file created using the record option gives me

Code: Select all

{"menu": [4568, 4455, 591, 1651, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 530, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 530, 591, 1651, 591, 530, 591, 530, 591, 1651, 591, 1651, 591, 1651, 591]}
but I still get the same type of stretching
irpystandard.PNG
irpystandard.PNG (10.72 KiB) Viewed 8041 times
giving it a simple file

Code: Select all

{"menu": [4500, 4500, 4500, 4500,4500, 4500]}

shows that instead of getting 9000 between gold and blue - its giving 10600

[attachment=0]irrp4500.PNG[/attachment
Attachments
irrp4500.PNG
irrp4500.PNG (19.74 KiB) Viewed 8041 times

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:12 pm

Hang on, I've just realised you aren't looking at the transmitted signal but you are looking at the received signal as processed by the IR receiver.

I'm looking at the transmitted carrier and the timing there is perfect.
454545.png
454545.png (46.88 KiB) Viewed 7997 times
mark - space - mark - space - mark = 4500 * 5 = 22500 µs expected

Measured = 22485 µs
Last edited by joan on Wed Jun 15, 2016 8:23 pm, edited 1 time in total.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:19 pm

Yes - I'm looking at received signal (receiver is on a Pi0 - tx is on a Pi3)

Sorry if I didn't make that clear :(

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:24 pm

mattmiller wrote:Yes - I'm looking at received signal (receiver is on a Pi0 - tx is on a Pi3)

Sorry if I didn't make that clear :(
Crossed posts, added image above.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:28 pm

However - its the tx timing that I'm having a problem with as I'm using the same Rx setup for all the tests

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:37 pm

mattmiller wrote:However - its the tx timing that I'm having a problem with as I'm using the same Rx setup for all the tests
Could you post the full LIRC numbers for "menu" and the corresponding numbers as recorded by irrp?

If irrp shows 10% higher that would explain the 10% more on transmission.

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 8:55 pm

The full LIRC tx numbers are

Code: Select all

          name KEY_MENU
             4560    4451     612    1632     607    1632
              607    1636     607     510     612     509
              612     510     611     510     607     514
              608    1635     608    1632     607    1632
              608     514     609     513     633     484
              612     520     597     515     607     515
              607    1632     632     489     634    1605
              611    1632     633     489     607     509
              613     516     601    1632     612     510
              611    1633     607     510     611     510
              612    1632     633    1606     632    1607
              611

      end raw_codes
and the irrp tx numbers are

Code: Select all

{"menu": [4568, 4455, 591, 1651, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 530, 591, 1651, 591, 1651, 591, 530, 591, 530, 591, 530, 591, 1651, 591, 530, 591, 1651, 591, 530, 591, 530, 591, 1651, 591, 1651, 591, 1651, 591]}
but I don't think this is the issue - any numbers I use get stretched out

I just installed PiScope on the transmitting Pi3 and its giving me the same results
irrp4500send.PNG
irrp4500send.PNG (20.48 KiB) Viewed 7902 times

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 9:00 pm

Just as an aside - I'm using a Pi3 as the tx so I'm going to swap my ir diode over to a PiZero and see if its the same on a different Pi

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 9:11 pm

not quite as stretched on the Pi0 but still 10000 instead of 9000
irrp4500sendpi0.PNG
irrp4500sendpi0.PNG (19.88 KiB) Viewed 7883 times

User avatar
joan
Posts: 14695
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 9:20 pm

Strange. I get exactly the same results on the Pi3 and on the Pi B+ I used before, exactly 22485 µs as before.

I'm using

data

Code: Select all

{"menu": [4500, 4500, 4500, 4500,4500, 4500]}
./irrp.py -p -g 4 -f data menu

Are you overclocking?

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 9:57 pm

Not overclocking

I'll try a fresh image and see what that does

Its a good one!

mattmiller
Posts: 2178
Joined: Thu Feb 05, 2015 11:25 pm

Re: Simple Infra-Red record/playback

Wed Jun 15, 2016 10:03 pm

I'm off to bed now - I'll report back tomorrow on what happens with fresh image with just irpy and piscope installed

Return to “General discussion”