Skip to content

Support RC receivers #1071

Closed
Closed

Description

@Resseguie

I'd like to add a class to support traditional hobby RC receivers to control nodebots. I happen to have a Spektrum radio and compatible receivers, but other popular Tx/Rx (transmitter/receiver - common abbreviations in RC world) combinations should be supported, too.

Details of my exact setup:
DX6 Radio: http://amzn.to/1Se2hjd
AR610 Rx: http://amzn.to/1UQfqVw
(There are Spektrum compatible Tx an Rx made by Orange that are much cheaper.)

It should support individual channels (like the AR610), but also the PPM (Pulse Position Modulation) varieties.

There are a number of examples of using these with Arduino that could get us started.
https://www.sparkfun.com/tutorials/348
http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html

How generic should such a component be?

Activity

  1. rwaldron commented on Mar 28, 2016

    @rwaldron
    Owner

    I've been casually thinking about this for about a year and the basic sketch I always return to is:

    • Receiver class
      • channels property, that's an array and the values are the most recently received value
    • Transmitter class
      • ?

    That's about as far as I usually get. It's critically important that these are designed with the controller pattern.

  2. Resseguie commented on Mar 28, 2016

    @Resseguie
    CollaboratorAuthor

    I'm not sure we need Transmitter? Seems like that's on "the other end" that we don't care about. At least I can't think of a use case. We just need to know the value the transmitter sends, via the receiver.

    I'll need to think through the channels property, to make sure that makes sense for PPM as well. (I think so, but want to think it through.)

  3. rwaldron commented on Mar 29, 2016

    @rwaldron
    Owner

    That may very well be the case, I just figured I'd put it there and we can let the junk shake out :)

  4. rwaldron commented on Mar 30, 2016

    @rwaldron
    Owner

    (There are Spektrum compatible Tx an Rx made by Orange that are much cheaper.)

    I just purchased these, should receive them tomorrow

  5. rwaldron commented on Mar 30, 2016

    @rwaldron
    Owner

    The major issue we face is that pulseIn is process blocking. Some things to consider:

    I like the idea of defining our own I2C backpacked peripheral, because we can control every aspect. I've come to realize that the design decisions made by many (not all) hardware creators is generally not very compatible with our async goals.

  6. henricavalcante commented on Mar 31, 2016

    @henricavalcante
    Contributor

    Is there a way to handle PPM signal over firmata?

  7. rwaldron commented on Mar 31, 2016

    @rwaldron
    Owner

    @henricavalcante no, but it can be made available via I2C

  8. rwaldron commented on Mar 31, 2016

    @rwaldron
    Owner

    @Resseguie

    I assembled this gizmo as a basic "backpack" starting point. In the photos below, you'll notice that the intention is to plug this thing directly into the receiver unit's channel pins. The fritzing shows everything facing forward, but that's just only for illustrative purposes (and a limitation of fritzing)






    G: Ground
    V: VCC
    C: Channel

    I haven't added a label for channels, because my actual receiver won't arrive until later today, so I'm not sure which direction the channels are in.

  9. Resseguie commented on Mar 31, 2016

    @Resseguie
    CollaboratorAuthor

    Nice. I'll try to build something similar.

  10. rwaldron commented on Mar 31, 2016

    @rwaldron
    Owner

    Welllllllll my receiver just arrived and unfortunately the one I ordered has notches

  11. rwaldron commented on Apr 1, 2016

    @rwaldron
    Owner

    I cut them out and made it fit. Then I made a newer, less messy backpack. Pictures later

  12. Resseguie commented on Apr 3, 2016

    @Resseguie
    CollaboratorAuthor

    That's the same Rx I have. FYI, the typical method for connecting such a receiver to your RC project (drone, truck, etc) is with a breakout cable, such as this Naze32 one: http://www.readymaderc.com/store/index.php?main_page=product_info&products_id=3062

    That also gives you more flexibility in positioning components on your build. I'll probably make my backpack to accept something similar to that.

    Note that weight is also a factor for many uses of this, so I'd like to investigate the minimum backpack necessary once we get the design working.

  13. rwaldron commented on Apr 4, 2016

    @rwaldron
    Owner

    The second one I built significantly reduced materials:







    FYI, the typical method for connecting such a receiver to your RC project (drone, truck, etc) is with a breakout cable, such as this Naze32 one: http://www.readymaderc.com/store/index.php?main_page=product_info&products_id=3062
    That also gives you more flexibility in positioning components on your build. I'll probably make my backpack to accept something similar to that.

    But you won't be able to use such a thing if you're trying to read the pulse values from the receiver—right? You're effectively replacing this thing and adding a "middle man" to intercept the pulses to do something else with them.

  14. 31 remaining items

  15. henricavalcante commented on Apr 6, 2016

    @henricavalcante
    Contributor

    @rwaldron have you tried like this:

    for (int i = 0; i < channels; i++) {
        noInterrupts();
        buffer[i * 2] = pulses[i] >> 8;
        buffer[i * 2 + 1] = pulses[i] & 0xFF;
        interrupts();
      } 
  16. rwaldron commented on Apr 6, 2016

    @rwaldron
    Owner

    I thought I did and I thought I saw it crashing. It's not crashing now.

  17. rwaldron commented on Apr 6, 2016

    @rwaldron
    Owner

    I'm signing off for a bit.

  18. rwaldron commented on Apr 6, 2016

    @rwaldron
    Owner

    Presently, this is not crashing:

    #define EI_ARDUINO_INTERRUPTED_PIN
    #include <EnableInterrupt.h>
    #include <Wire.h>
    
    #define DEBUG_MODE 1
    
    // Address Pins
    #define AD0 11
    #define AD1 12
    
    // I2C Defaults
    #define I2C_DEFAULT_ADDRESS 0x0A
    #define I2C_BUFFER_SIZE 16
    
    byte buffer[I2C_BUFFER_SIZE];
    
    int addressPins[] = { AD0, AD1 };
    int address = I2C_DEFAULT_ADDRESS;
    int first = 2;
    int channels = 8;
    
    volatile int pulses[8];
    volatile int last_up[8];
    
    void up() {
      volatile uint8_t pin = arduinoInterruptedPin;
      enableInterrupt(pin, &down, FALLING);
      last_up[pin - first] = micros();
    }
    
    void down() {
      volatile uint8_t pin = arduinoInterruptedPin;
      enableInterrupt(pin, &up, RISING);
      pulses[pin - first] = micros() - last_up[pin - first];
    }
    
    void resetState() {
      for (int i = first; i < first + channels; i++) {
        pulses[i - first] = 0;
        last_up[i - first] = 0;
    
        pinMode(i, INPUT_PULLUP);
        enableInterrupt(i, &up, RISING);
      }
    }
    
    void setup() {
    
      // First check if the address was set via pins 11 or 12
      int offset = 0;
    
      for (int i = 0; i < 2; i++) {
        pinMode(addressPins[i], INPUT);
        if (digitalRead(addressPins[i])) {
          offset |= 1 << i;
        }
      }
    
      address += offset;
    
      resetState();
    
      #if DEBUG_MODE
        Serial.begin(9600);
      #endif
    
      // Initialize Slave
      Wire.begin(address);
      Wire.onRequest(onRequest);
      Wire.onReceive(onReceive);
    }
    
    void loop() {
      #if DEBUG_MODE
        for (int i = first; i < first + channels - 1; i++) {
          Serial.print(pulses[i - first]);
          Serial.print("  - ");
        }
        Serial.println(pulses[channels - 1]);
      #endif
      for (int i = 0; i < channels; i++) {
        noInterrupts();
        buffer[i * 2] = pulses[i] >> 8;
        buffer[i * 2 + 1] = pulses[i] & 0xFF;
        interrupts();
      }
    }
    
    void onRequest() {
      Wire.write(buffer, I2C_BUFFER_SIZE);
    }
    
    void onReceive(int count) {
      while (Wire.available()) {
        // Command 0x01 => Reset.
        if (Wire.read() == 0x01) {
          Serial.println("RESET");
          resetState();
        }
      }
    }
  19. henricavalcante commented on Apr 6, 2016

    @henricavalcante
    Contributor

    It's not crashing here too, which node code are you using in tessel 2 to get values from I2C?

  20. rwaldron commented on Apr 6, 2016

    @rwaldron
    Owner

    I've been working on a plugin component Receiver class all day, I will push it out tomorrow. I have to leave my computer for the rest of the day.

  21. henricavalcante commented on Apr 6, 2016

    @henricavalcante
    Contributor

    ok I'll wait until tomorrow ;)
    I was trying something like this without success:

    const five = require('johnny-five');
    const board = new five.Board();
    
    board.on('ready', function(){
      const opts = {
        address: 0x0A
      };
    
      this.io.i2cConfig(opts);
    
      this.io.i2cRead(opts.address, 16, function(data) {
        console.log(data);
      })
    });
  22. Resseguie commented on Apr 7, 2016

    @Resseguie
    CollaboratorAuthor

    Looks like I was away for a few days and missed some fun discussion.

    Regarding that Naze cable:

    But you won't be able to use such a thing if you're trying to read the pulse values from the receiver—right? You're effectively replacing this thing and adding a "middle man" to intercept the pulses to do something else with them.

    I really only meant that I'll probably have male pins on my backpack so I could use such a cable since you can get something similar for most receivers. Then you don't have to worry about having female headers shaped a specific way to fit a particular receiver onto a backpack.

  23. rwaldron commented on Apr 8, 2016

    @rwaldron
    Owner

    @Resseguie got it!

  24. rwaldron commented on Apr 8, 2016

    @rwaldron
    Owner
  25. henricavalcante commented on Apr 8, 2016

    @henricavalcante
    Contributor

    I'll test asap. btw great work. =)

  26. rwaldron commented on Apr 9, 2016

    @rwaldron
    Owner

    Thanks! It's pretty fun :D

  27. dtex commented on Jan 8, 2018

    @dtex
    Collaborator

    This just landed in configurableFirmata https://github.com/git-developer/RCSwitchFirmata Seemed relevant.

  28. dtex commented on Jan 11, 2018

    @dtex
    Collaborator

    Hi @Resseguie,

    I'm working on cleaning up the J5 issues list (it was getting kind of hairy). I've identified a subset of issues that are requests for new classes, devices or features and have added them to an index of requested features. Hopefully it will be a place where motivated contributors can find cool things to work on.

    This request is listed under the new "Receiver" class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions