Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Received value always "0" #55

Closed
nbigaouette opened this issue Feb 14, 2021 · 15 comments
Closed

Received value always "0" #55

nbigaouette opened this issue Feb 14, 2021 · 15 comments
Labels

Comments

@nbigaouette
Copy link

Hi! Thanks for this crate. I am new to embedded rust and thus bought this kit: https://www.amazon.ca/-/fr/gp/product/B07CVS1LBT

It's an Arduino Uno controlling the car. While the original C code is fully functional, I want to write my own Rust firmware.

My first step is to read infrared commands from the remote but I am having issues. I struggled to even get something since your example uses a bluepill instead of an arduino so I am trying to understand how the infrared receiver works. The avr-hal crate I am using (https://github.com/Rahix/avr-hal) does not seems to be handle interupts which you example uses...

It seems that the PeriodicReceiver::new()'s sample rate must match the delay between two successive calls to poll(). So for a 20kHz rate, I need to arduino_uno::delay_us(50); in my loop (1 / 20kHz = 50 mus):

loop {
    if let Ok(Some(cmd)) = ir_receiver.poll() {
        ufmt::uwriteln!(&mut serial, "{:?}", cmd.bits).void_unwrap();
    }

    // 20 kHz == period of 50 mus
    // The delay between polling must match the receiver's sample rate
    arduino_uno::delay_us(50);
}

If I change the delay by 1 mus, poll() returns an Err... Is that expected?

Using the arduino's "IRremote" library's IRrecvDump example I see the following in the serial console when I press the button "1" of the remote:

FD00FF
Decoded NEC: FD00FF (32 bits)
Raw (68): 5682 8950 -4450 600 -550 550 -600 550 -550 600 -500 600 -550 600 -500 600 -550 600 -500 600 -1600 600 -1600 650 -1600 600 -1600 600 -1600 600 -1600 650 -500 600 -1600 600 -550 550 -600 550 -550 550 -600 550 -550 550 -550 600 -550 550 -550 600 -1650 550 -1650 550 -1650 550 -1700 550 -1650 550 -1650 550 -1650 600 -1650 550 

From this I understand the protocol is NEC. I thus define my receiver as:

// The specs says the IR received is on pin D2
let mut ir_receiver: PeriodicReceiver<NecDebug, PD2<Input<Floating>>> = PeriodicReceiver::new(pins.d2, IR_SAMPLERATE);

I tried both Nec and NecDebug: The cmd+addr and bits are always 0. :(

The NecDebug::repeat does seems to work though; a short press gives me false while a long press gives true.

Am I missing something obvious?

Thanks a lot!!

@nbigaouette
Copy link
Author

I've pushed the code to a new repo, might be clearer than out of context snippets above.

See https://github.com/nbigaouette/robot-car/blob/343b89bc397dc99761de583d744ebe8d/rust/spot/src/main.rs

@jkristell
Copy link
Owner

Hi and thanks for testing this on AVR!

If my parsing of the output from IRrecvDump correctly it seems to be standard NEC, so Infrared should be able to handle it. And as it looks like both command and repeats are recognized, but the data is incorrectly parsed. Weird.

My initial guess was that the avr-hal's delay_us() were to inaccurate (sometimes they only guarantee that they will delay for at least that amount of time), but as the Headers for the command for both Repat and Command are recognized, that seems to be ok.

My second guess is that Infrared's tolerances is too tight, but then again, then you wouldn't have gotten a Ok(Some(cmd)) response from poll().

So it could be a bug in Infrared, I'm gonna write some test code with the data you posted and see if I can figure out what is going on.

@nbigaouette
Copy link
Author

Fantastic! Thanks for your help 👍

I'm attaching all the IR codes of my remote I've dumped from IRrecvDump. In the file, I've put the button I've pressed to get the dumped value. For example:

Left
Decoded NEC: FD9867 (32 bits)
Raw (68): 4142 9000 -4400 600 -550 600 -550 550 -550 600 -550 550 -550 550 -600 550 -550 550 -600 550 -1600 600 -1650 550 -1650 600 -1600 600 -1650 550 -1650 600 -550 550 -1650 600 -1650 550 -550 550 -600 550 -1650 550 -1650 550 -600 550 -550 550 -600 550 -550 550 -1650 600 -1650 550 -550 550 -600 550 -1650 550 -1650 550 -1700 550 

is the output I got when pressing the Left button on the remote. The following two lines are the output of IRrecvDump.
ir_codes.txt. The file is also on github.

Hopefully that should help you out...

Thanks again!

@nbigaouette
Copy link
Author

If I look at the IR receiver initialization from the original C++ code: https://github.com/nbigaouette/robot-car/blob/343b89bc397dc99761de583d744ebe8d47dfd135/initial_code/sdk/Smart%20robot%20car%20comprehensive_Experiment/Comprehensive_Experiment/IRremote.cpp#L272-L294
there some interrupt and timers initialization... Should I be setting those too in my Rust code? Or is infrared supposed to be initializing things by itself?

@jkristell
Copy link
Owner

I did a quick test with the data you posted above and in the text file, and Infrared seems to parse it just right - https://gist.github.com/jkristell/4abf47e36a789c1be05ae579be71dd6b

So it's probably some kind of timing problem, with running the code in the main loop. Could you try the next-branch of Infrared?
That should work better with the AVR as I removed some costly operations in the hot path.

Setting up the interrupt and calling poll() from a periodic interrupt is probably the way to go. Unfortunately timers in AVR-hal is not that great :).

As a side note:
I started a project where I tried to get an AVR based remote control up and running with Infrared as the IR driver. https://github.com/jkristell/rustyremote

But the project stalled when I needed to setup a timer and realized there was no infrastructe in avr-hal to do it. My plan was to get back to it and at least implement my own timer that I could use in the project.

@jkristell
Copy link
Owner

Example of using the "next" branch:

https://github.com/jkristell/infrared-examples/blob/infrared-r0.11/stm32f103-bluepill/Cargo.toml

Don't forget to change the infrared version in dependency list.

@nbigaouette
Copy link
Author

After consulting with an expert friend, using a sleep is not ok to do what I wanted to do. I needed to go down the interrupt route.

After some head scratching (and some help from https://github.com/Rahix/avr-hal/blob/bfc950428919af96030e66e9b44af2b4574a1ec1/boards/arduino-uno/examples/uno-millis.rs) I came up with this: https://github.com/nbigaouette/robot-car/blob/343560dbacca67d643a6cb6c17ad5eaf/rust/spot/src/main.rs

Now it "seems" to work.

With the code above, I get the following output when I press the buttons one after the other (1, 2, 3, 4, 5, 6, 7, 8, 9, *, 0, #, Up, Left, Ok, Right, Down):

Initializing Arduino Uno...
6 161 true
6 161 true
134 161 true
78 161 true
134 161 true
78 161 true
54 161 true
78 161 true
38 161 true
46 161 true
78 161 true
54 161 true
54 161 true
30 161 true
38 161 true
30 161 true
46 161 true

What surprised me (except that I get something! 😂 ) is that:

  • the addr value changes while the cmd stays at 161.
  • the repeat is always true.
  • there is some keys that are duplicated, for example the first two key presses (1 and 2).

I'm not sure I can say that "it works" yet...

@jkristell
Copy link
Owner

Hi

I bought an Arduino Uno to test this as well. The example code I wrote is here: https://github.com/jkristell/infrared-examples/blob/add-arduino-example/arduino_uno/src/main.rs

And I get the same error as you. The reason for the weird result is that Infrared successfully parse some bits in the command, then fails because of some timing issue, but, the bits are saved in the bitbuf and returned as a command when Infrared sees the repeat code, on the next button press.

So this is a Infrared bug (the bitbuf should be cleared on error), but a bug that at least helps us to understand what's happening.

I am gonna add some infrastructure to Infrared to do capturing of the pulses, and do offline print/debug of them, that should help figuring out why this fails.

@jkristell
Copy link
Owner

jkristell commented Feb 22, 2021

Another thing I found. Rc5 works fine, but none of the other protocols :)

@jkristell
Copy link
Owner

jkristell commented Feb 22, 2021

Another live update. If I only do capture on the pin and print the data "offline", after the receive, the data looks Ok.

But if i then create a BufferReceiver and try to parse the buffer, it fails too. I think this indicates some problem with the AVR Rustc AVR backend, I'm gonna try changing all internal u32 types to usize/u16 and see what happens.

My suspicion is that my use of Range somehow creates this problem.

@nbigaouette
Copy link
Author

Wow thanks for your investigation!! I do hope it's not the AVR backend, as that's quite deep in the stack :S

Please let me know of your investigation!

Thanks again ;)

@jkristell
Copy link
Owner

Ok, so a small update.

If I just capture the pulses in the interrupt and do the decoding in the main-loop, it seems to work on my hacked up version.

I could try to polish up this and create a example for you to use. Not ideal, but a solution :).

@nbigaouette
Copy link
Author

That'd be great!

@jkristell jkristell added the AVR label Mar 6, 2021
@jkristell
Copy link
Owner

jkristell commented Mar 6, 2021

Possible related:
rust-lang/rust#82242

@jkristell
Copy link
Owner

I finally found the problem. It was the shift of the u32 as described in the rust-lang bug. And that was the reason rc5 worked the whole time, but not the other protocols, as Rc5 used u16 internally to save the received data.

I have created a branch https://github.com/jkristell/infrared/tree/avr with a hacky version that supports Nec (only the standard variant) as well as Rc5 and Rc6.

Example on how to use it can be found here: https://github.com/jkristell/infrared-examples/tree/add-arduino-example/arduino_uno

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants