Closed water5 closed 2 years ago
I can't replicate this. I suspect you have an outdated file, possibly __init__.py
?
MicroPython v1.17 on 2021-09-07; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> from machine import Pin
>>> from ir_tx.nec import NEC
>>> nec = NEC(Pin(23, Pin.OUT, value = 0))
>>>
I try RPi PICO use same version of ir_tx library, https://github.com/peterhinch/micropython_ir/commit/2ebf5db498266618fc0f037469309a6ea1906304, works fine, the __init__.py
line 45,
self._rmt = RMT(0, pin=pin, clock_div=80, carrier_freq=cfreq, carrier_duty_percent=duty) # 1μs resolution
but with ESP32 not, used incorrect parameter.
The latest esp32.RMT module has new parameter:
class esp32.RMT(channel, *, pin=None, clock_div=8, idle_level=False, tx_carrier=None)
Change to
self._rmt = RMT(0, pin=pin, clock_div=80, tx_carrier = (cfreq, duty, 1))
but rise error:
from ir_tx.nec import NEC
nec = NEC(Pin(23, Pin.OUT, value = 0))
nec.transmit(1, 2)
Traceback (most recent call last): File "stdin", line 1, in module File "/lib/ir_tx/init.py", line 90, in transmit File "/lib/ir_tx/init.py", line 98, in trigger TypeError: function doesn't take keyword arguments
Oh dear, the maintainers have changed the calling conventions. It may be a little while before I can address this. On the face of it the above error can be fixed by changing lin 98 of __init__.py
to read:
self._rmt.write_pulses(tuple(self._mva[0 : self.aptr]))
If you feel like submitting a PR with tested fixes I'll be pleased to merge it :)
I try it. :)
I've checked my micropython_remote repo which has been updated to handle the API changes. This has this line so I think the above should work.
What difference between micropython_remote and micropython_ir?
The micropython_remote repo is for 433MHz radio controlled remotes. It is very different because there are no published standards for these. You have to use a radio receiver to capture signals from the transmitter so that you can replay them. The receivers are a great way to safely switch mains devices under program control.
Have the changes we discussed worked OK?
Hello again, Peter!
I can help with this.
After our recent asyncio documentation adventure, I returned to a project I started 6 months ago with more confidence: building an IR transmitter to augment my monitor's remote control. I intended to create a small box with button 'presets' that would allow me to set the brightness so that I would not have to hold the button down for long periods of time. Why? With each power-on/power-off or input change, the settings are reset.
~5 years ago I had built an IR transmitter project using Arduino to control a duct fan, so I was sure that with micropython I could put this together in no time. However, I put the project in a drawer because I could not get the IR transmit function working correctly with my RPI Pico. At the time, I was successfully able to capture the remote's 24 button codes - it used simple NEC_8 formatted codes, but I was unable to use the ir-tx library to send them. I wasn't sure if I had to send them as hex, or if integers were sufficient since the test.py formats them as hex; maybe aligning these would help future users. I thought about raising an issue, but wanted to make 100% sure that my circuit and code was correct before troubling maintainers.
Today, I built up a simple circuit with a BC547, an IR LED (clear; I'm unsure of the wavelength, but I have several tinted ones which don't work), a 33 Ohm current limiting resistor, an external breadboard 5 V supply, and a 1 K Ohm resistor between the transistor's base and the GPIO pin. Using a cellphone, I was able to observe the flashes of IR light, however the monitor did not respond :(. Also, with my IR receiver powered, I saw the on-board led reacting, but I couldn't be sure if this was just noise. I knew that IR devices can be tricky. On my previous Arduino IR fan project, I remembered that I had captured the raw remote codes because I couldn't get whatever library I was using to work and even then I ended up needing to play each code 3 times for them to be identified by the fan.
I tried setting up this code to loop through with my Pico to see if the monitor would react.
import time
from ir_tx.nec import NEC
nec = NEC(Pin(17, Pin.OUT, value = 0))
dict_of_codes = {
"Volume Up":25,
### More omitted
}
addr=96
while True:
for function in dict_of_codes:
print(function, addr, dict_of_codes[function])
nec.transmit(addr=96,data=dict_of_codes[function])
time.sleep(1)
Unfortunately this didn't work, but I was fairly confident my circuit was correct; I even pulled my old project apart to inspect the transistor package orientation (Youtuber Noel's Retro Lab recently had a video about different vendors changing transistor orientations) and resistor values. Defeated, I decided to go back to the documentation, which led me to... Transmitter Section 5 - Unsupported Protocols. I copied the raw capture code to Thonny, started the script, pressed a button on my remote, and got this output saved to the burst.py file: [8885, 4530, 516, 611, 517, 611, 612, 514, 516, 611, 515, 612, 514, 1749, 511, 1743, 517, 616, 514, 1744, 514, 1744, 516, 1744, 517, 1743, 516, 1742, 517, 611, 515, 612, 515, 1746, 517, 1743, 516, 612, 514, 612, 515, 1744, 516, 1742, 518, 609, 516, 612, 515, 615, 516, 611, 515, 1793, 466, 1745, 515, 612, 515, 610, 568, 1690, 516, 1744, 515, 1745, 516] I then proceeded to attempt playback.
File "<stdin>", line 11, in <module>
File "ir_tx/__init__.py", line 126, in __init__
File "ir_tx/__init__.py", line 45, in __init__
TypeError: extra keyword arguments given
self._rmt = RMT(0, pin=pin, clock_div=80, tx_carrier=(cfreq, duty, 1))
and line 99 must be changed to:
self._rmt.write_pulses(tuple(self._mva[0 : self.aptr]))
With those changes, the script replied fine. In addition, the script using nec.transmit worked fine too, but only on the ESP32 (with pin 23), however, when I switched back to the RPI Pico, it still did not work.
So for me, water5 and your solutions are working for the ESP32, but I don't know what's wrong with the Pico.
Thanks for confirming that the latest code works on ESP32.
I'm not sure what to say about the Pico: in my testing and that of @water5 the Pico works. It's hard to debug these things remotely :)
You're welcome, Peter.
Yes, I know debugging remotely can be difficult. However, I'm concerned there is a bug in the transmit code for the RP2 routines. <Should I open a new issue?>
IR tx works on the ESP32, but IR tx on the RP2 doesn't. I tried to set up an experiment which I could repeat four times. The table at the end of this post uses these shorthand names:
tx code (manually entered into the REPL console using Thonny)
from machine import Pin
from ir_tx.nec import NEC
nec = NEC(Pin(16, Pin.OUT, value = 0)) # Pin 16 on RPI2, Pin 23 on ESP32
nec.transmit(addr=96,data=93)
I created four capture_raw python files - two for the RP2 and two for the ESP32 results. This was useful when comparing console output and consolidating the information. I ran these using Thonny's "Run current script" option.
capture_raw_ir_code_xxx_from_yyy.py contents
from ir_rx.acquire import test
import ujson
lst = test() # May report unsupported or unknown protocol
with open('XXXX_from_YYYY.py', 'w') as f:
ujson.dump(lst, f)
The output files were:
Legend: Column 1 is the event Column 2 is the ESP32 capture from the remote Column 3 is the ESP32 capture from the RP2 (nec.transmit) Column 4 is the RP2 capture from the remote Column 5 is the RP2 capture from the ESP32 (nec.transmit)
TIME ESP-RM ESP-RP2 RP2-RM RP2-ESP
--- NEC Unkn NEC NEC
000 8938 8988 9028 9010
001 4508 4363 4453 4414
002 571 629 568 630
003 552 561 555 500
004 574 550 563 632
005 554 515 561 470
006 603 626 570 662
007 520 508 559 490
008 576 633 566 603
009 553 513 558 507
010 573 2205 518 544
011 553 1712 618 608
012 620 231 517 571
013 1735 209 1735 1669
014 476 286 570 593
015 1691 985 1684 1646
016 567 627 577 592
017 564 557 558 556
018 566 555 568 584
019 1688 1659 1689 1659
020 576 625 570 599
021 1683 1628 1700 1644
022 576 662 562 625
023 1769 1609 1687 1630
024 487 590 570 596
025 1691 1649 1723 1650
026 567 607 537 626
027 1692 1644 1695 1614
028 696 611 570 649
029 428 507 555 473
030 575 634 567 583
031 551 509 558 549
032 574 633 572 590
033 1687 1617 1695 1653
034 576 638 566 619
035 1681 1623 1693 1646
036 580 632 565 586
037 551 526 562 513
038 574 589 568 616
039 1685 1644 1685 1675
040 695 612 573 585
041 1560 1667 1688 1671
042 580 588 571 609
043 1683 1644 1691 1611
044 575 612 564 614
045 552 715 565 513
046 571 399 566 627
047 1693 7325 1691 1610
048 567 2525 524 657
049 564 1371 608 481
050 565 309 518 609
051 560 488 607 514
052 684 1121 521 522
053 1571 229 1740 1713
054 576 166 517 664
055 550 1058 610 475
056 575 308 515 661
057 553 176 609 470
058 574 1075 518 615
059 552 1259 607 511
060 571 2153 521 594
061 1692 162 1748 1642
062 567 231 513 659
063 559 END 602 492
064 567 END 524 606
065 1688 END 1740 1638
066 576 END 522 633
END = Did not exist
Lengths: Col 2 esp-rm 68201 Col 3 esp-rp2 72282 Col 4 rp2-rm 68188 Col 5 rp2-esp 68072
Something is really wrong here with this nec.transmit() function:
After reviewing the Altium - NEC Infrared Transmission Protocol page, I can see:
That's as far as I can go without diving deeper into how the transmit function works.
I can't replicate this.
I have verified that the bit patterns in your columns labelled NEC are correct for the values of address and data you are using. However with a logic analyser on pin 16 of a Pico, and pasting your exact transmit code I see the same correct bit pattern:
from machine import Pin
from ir_tx.nec import NEC
nec = NEC(Pin(16, Pin.OUT, value = 0)) # Pin 16 on RPI2, Pin 23 on ESP32
nec.transmit(addr=96,data=93)
This is the start of the waveform (note that what we are seeing here are bursts of carrier):
and here are the data bits, the trace starting with the trailing end of the 4.5ms off start state:
I suspect you have some kind of communication problem between transmitter and receiver, but it's impossible for me to check this remotely.
Thank you, Peter.
I tried to rule out user error and re-read the documentation from scratch. I cannot find any setting, or configuration which made any difference. I even tried v1.18 (2022-01-17). I did discover that my ESP32S will power the IR LED without the transistor circuit. I'm not sure about the RP2, I see it flash on camera, but the signal doesn't register (as usual). While I do have an air conditioning unit in the same room which periodically syncs temperature data with the remote, it shouldn't cause shorter timing coming out of the RP2.
This is really quite baffling. For months I thought this was my own user error, but seeing it work on the ESP32S makes me doubt it. I checked with the verbose class flag, and the data being appended is identical across both devices (as expected). I have an old habit of going through code and inserting print() statements to better understand what's happening, but everything looks the same, except for the timeit() function takes longer on the ESP32, which might be due to the older architecture.
The only difference I see is that the ESP32 uses RMT, whereas the RP2 uses RP2_RMT. Of course, the underlying architectures are likely totally different. I really didn't plan on learning how the RPI_RMT module and PIO worked, but maybe that's my next step to see if I can alter the timing output. This was touted as one of the main selling points of the RP2040.
This is a long shot, but which silicon stepping of RP2040 do you have? I have two RP2040B1 devices on my RPI Picos. Other than a) an undiscovered silicon issue, b) different onboard crystals impacting silicon operation, c) an existing errata impacting this (maybe the watchdog timer one noted in the datasheet), d) some other production-related variable which we cannot determine.
Just for reference, here is one of my device's unique ID:
machine.unique_id() b'\xe6
\xa4\x93\x17Xj&'`
I don't know if this number is incremented as units are produced, but I do find it amusing that the first 2 bytes are 椓 = beat... this thing sure is beating me up. I might try go picking up some RPI Picos from a different vendor to see if that will make a difference.
I really don't see what else it could be. Maybe not many people have used Picos for IR projects? I found 0 examples on YouTube of IR transmit functions and even fewer results on google.
This might finally be an excuse to buy an oscilloscope. I saw the YouTuber Adrian's Digital Basement Demo a 60 USD Unit recently.
which silicon stepping of RP2040 do you have?
How can I determine this?
I think it's unlikely that it's that sort of problem. My usage of the PIO is straightforward. I've found it entirely reliable and I've heard no complaints about it on the forum. I would investigate your electronics first.
An oscilloscope would make this a lot easier, preferably a digital storage scope. In your position I would examine the waveform at the pin, with the pin unconnected, as I did. Assuming it's correct, then add your electronics and check again. I would definitely not drive the LED without a transistor or MOSFET buffer (on any platform). Note that my suggested designs use voltages higher than 3.3V: this is to ensure adequate drive for the LED. The fact that you can detect a flash says nothing about whether it is getting a clean pulse.
which silicon stepping of RP2040 do you have?
How can I determine this? I used my phone to take a picture of the RP2040 package on the board. With just the correct angle I was able to capture the laser engraving.
I'll see if I can capture the output with an oscilloscope in the next few days.
esp32.RMT module already updated, some arguments changed, https://docs.micropython.org/en/latest/library/esp32.html?highlight=rmt#esp32.RMT
When ir_tx instance initialize, rise error below: