6

I've been struggling for a few days and haven't managed to turn up a lot on the internet. I'm looking to READ from the PWM output of an RC receiver through one of the GPIO's on the RPi. I've read other questions where it's not suitable for "serious" PWM but I'm not looking to use it as an output. Looking at the WiringPi library, I've found functions that allow me to write out PWM, but I'm having a hard time getting anything off the GPIOs, even with generic reads. It feels like I should be able to do something like this tutorial here, but I've not had any luck. Am I just trying to do something that's beyond what any libraries have provided at this point or is there something stupid simple I'm missing before I have to dig down into writing assembly code to interface with the thing?

Wyatt
  • 83
  • 1
  • 6

5 Answers5

3

I can't answer to your question directly, but I can try to answer to Alex Chamberlain's answer.

Obtaining hard real-time capabilities in Linux, down to sub-millisecond resolution, is possible. To do that, a patch or a set of patches must be applied to the kernel sources. To cite a few, one can use Ingo Molnar's RT-Preempt Patch, Xenomai, RTAI or ADEOS. You can find more information here, here and here.

Avio
  • 1,217
  • 2
  • 14
  • 25
1

This does a fairly accurate job of reading pwm fq and dutyCycle, as long as the signal is < 50hz:

#!/usr/bin/python2.7

import RPi.GPIO as gpio
from datetime import datetime
from time import sleep, time



gpio.setmode(gpio.BCM)
gpio.setup(2, gpio.IN)
global risingCount
global pulseWidth
global timeStart
risingCount = 0
pulseWidth=0
timeStart=0

def edgeDetected(channel):

    global risingCount
    global pulseWidth
    global timeStart

    if gpio.input(2):
        #rising edge
        risingCount += 1
        timeStart = time()
    else:
        #falling edge
        if (risingCount != 0):
            timePassed = time() - timeStart
            #make pulseWidth an average
            pulseWidth = ((pulseWidth*(risingCount-1)) + timePassed)/risingCount


gpio.add_event_detect(2, gpio.BOTH, callback=edgeDetected)


while True:
    sleep(1)
    print "PWM = {0}hz, dutyCycle = {1}%".format(risingCount, round(pulseWidth*risingCount*100,2))
    risingCount = 0
    pulseWidth = 0

I believe you can increase accuracy by increasing the sleep time (remember to multiply hz with 1/sleep time) for larger averages.

mapt
  • 11
  • 2
1

It's not possible. In order to do this, you need accurate timing, which isn't possible on Linux.

Your best bet is to work out how to do this on a separate micro and communicate with the Raspberry Pi over SPI or I2C. There may even be an existing IC for this.

Alex Chamberlain
  • 15,530
  • 14
  • 67
  • 113
1

You can follow this tutuorial: https://www.sparkfun.com/tutorials/348 and than the only thing todo is write this data via usb to your raspberry pi. Happy coding :)

veroy
  • 21
  • 1
  • Welcome to Raspberry Pi! Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. Also a tutorial aimed at the arduino may leave the OP with more questions than answers. – Steve Robillard Aug 18 '15 at 19:26
1

My understanding of reading PWM signals for non-realtime systems has been to treat them as analog voltages (that's right, run it through an RC circuit and then read the voltage using an analog-digital converter/ADC).

Apropos: http://www.instructables.com/id/Arduino-RC-Circuit-PWM-to-analog-DC/?ALLSTEPS

More engineering work, sure, but cheaper than bolting on an Arduino to do the realtime chore of reading PWM pulses with a pin change interrupt: http://www.benripley.com/diy/arduino/three-ways-to-read-a-pwm-signal-with-arduino/

WineSoaked
  • 350
  • 2
  • 10