Entrée PWM dans Raspberry Pi

10

Existe-t-il un moyen de lire un signal PWM à partir des broches du Raspberry Pi?

J'ai essayé de le googler, mais je n'ai trouvé que la sortie PWM et non l' entrée .

Caio Keto
la source

Réponses:

4

La réponse courte: vous NE POUVEZ PAS lire de manière fiable PWM sur Raspberry Pi.

La lecture de PWM nécessite une précision en microsecondes (sauf si vous lisez un PWM très-très lent), et cela n'est pas disponible sur Raspberry Pi pour les logiciels utilisateur sans bricoler avec les modules du noyau.

La façon la plus simple de capturer du PWM serait d'obtenir n'importe quel microcontrôleur bon marché (<0,5 $) avec une sortie série ou I 2 C et de le raccorder à votre Raspberry Pi et de lire les valeurs réelles du microcontrôleur. Cela fonctionnera de manière très fiable et est assez précis.

lenik
la source
1
Une idée où obtenir un tel IC?
Pepijn
@Pepijn ce que vous cherchez est un convertisseur analogique-numérique (ADC). Un très commun que j'utilise très fréquemment est le MCP3008 8 canaux, 10 bits, et un autre que j'ai en permanence sur mon unité testant Pi pour mon logiciel Perl est le ADS1115 4 canaux, 16 bits. Ce dernier a besoin d'un peu de soudure, le premier non. Il existe de nombreux exemples de code disponibles pour utiliser ces deux unités (C, Python, Perl, etc.), donc si vous ne voulez pas / ne pouvez pas écrire le vôtre, cela devrait être trivial de commencer.
stevieb
N'importe quel microcontrôleur simple fera l'affaire. J'utilisais les produits Microchip pour ce genre de choses. L'avènement de l'Arduino a redonné de la popularité aux puces AVR. Maintenant, j'utilise simplement une petite carte de dérivation contenant un microcontrôleur et tout ce dont la puce a besoin. Mon préféré est la série Teensy 3.x.
NomadMaker
3

Je peux faire une mesure de largeur d'impulsion assez précise en utilisant la bibliothèque piGpio C: http://abyz.me.uk/rpi/pigpio/index.html

Cette bibliothèque vous permet d'installer une fonction de rappel qui se déclenchera sur n'importe quelle transition de front sur une broche gpio et vous donne un horodatage de niveau microseconde pour chaque transition. Ne pensez pas que vous pouvez compter sur cela pour une précision en microsecondes - mais mes tests suggèrent que la précision est d'au moins +/- 10us, peut-être mieux.

Beaucoup mieux que d'exécuter une boucle occupée interrogeant un gpio pour le changement de niveau vous-même.

stevec
la source
+1 Il convient de noter que la précision peut varier en fonction de la charge du processeur (en particulier les cœurs uniques), mais sinon, c'est une bonne réponse. :)
Jacobm001
Merci stevec, cette réponse est bien meilleure que de dire "ça ne peut pas être fait". Voir ma réponse séparée pour plus d'informations, y compris le code réel (c'est très court).
Georgie
2

C'est une question intéressante et vous avez raison de dire que la recherche Google ne fournit pas de solution évidente! (Je regrette les jours où Google pouvait répondre à tout ce que je voulais savoir pour mes études / devoirs en quelques secondes.)

Je suppose que vous comprenez les principes du PWM . Par conséquent, je n'entrerai pas là-dedans. Cependant, je pense que vous pourriez en théorie lire une valeur PWM sur une broche d'entrée numérique régulière avec un codage intelligent.

Je dois admettre que je n'ai pas essayé cela moi-même, mais vous devriez pouvoir mesurer le temps pendant lequel la broche est élevée et le temps pendant lequel elle est faible (en vous donnant votre lecture PWM), puis utiliser la formule mathématique fournie par le fournisseur du capteur pour le convertir en lecture réelle.

Cette méthode fonctionne pour moi sur un problème similaire où je devais lire la longueur d'impulsion d'un module à ultrasons puis la convertir en distance. Les problèmes que je peux envisager consistent à assurer des lectures fiables!

Si vous pensez que cela vous aidera et que vous souhaitez voir le code que j'ai utilisé pour le module à ultrasons, dites-le, et je le copierai à mon retour à la maison.

J'ai commencé à copier le code mais pour une raison quelconque, le site Web ne me permet de le copier qu'une petite section à la fois (et je suis trop paresseux pour sortir mon pi du garage) alors voici le lien vers celui-ci. ignorez la plupart des fonctions en bas car elles sont liées à l'utilisation du module comme capteur de proximité. http://pibot.webnode.com/products/ultrasonic-range-sensor/

D Mason
la source
Ce sera bien de voir le code, donc je peux avoir une base pour commencer mon propre code, si vous pouvez coller ici, je serai très reconnaissant ^^
Caio Keto
Le problème avec cette suggestion est que le noyau Linux ne vous donne pas suffisamment de temps pour lire les cycles de fonctionnement RC PWM typiques (qui sont généralement de 1000 à 2000 microsecondes toutes les 16 millisecondes) avec une précision suffisante. Si nous pouvions installer un gestionnaire d'interruption pour un changement de broche GPIO et capturer l'horodatage sur les transitions hautes / basses, dans un module du noyau, alors cela pourrait être une solution utile.
Jon Watte
1

La réponse longue: vous pouvez vraiment! (bien avec un peu d'aide de nos amis résistance et condensateur)

Vous pouvez convertir une sortie PWM en un niveau de tension analogique (DAC) et le lire avec la broche ADC sur votre raspberry pi.

Ce dont vous avez besoin est une résistance 4k7 et un condensateur 0,1uF:

schématique

simuler ce circuit - Schéma créé à l'aide de CircuitLab

Le simple filtre passe-bas RC ci-dessus convertit le signal PWM en une tension proportionnelle au rapport cyclique qui peut être lue par votre Raspberry Pi comme une valeur analogique.

Quête
la source
4
La broche ADC? Et ce serait quoi?
Ghanima
@Ghanima Eh bien, le nouveau pilote Microsoft Lightning est en cours de développement, mais sert assez bien à cet effet (il est documenté sur leurs pages). Pour ce que j'ai trouvé pour BCM2837 il pourrait avoir un ADC matériel qui est sur GPIO0 (malheureusement celui - ci est lié à aucune broche d' en- tête) .. au moins ils liés matériel canaux MLI
Quête
0

Si vous êtes satisfait d'une réponse lente, vous pouvez lire un PWM rapide par sous-échantillonnage. Lisez simplement le GPIO en boucle et appliquez un filtre passe-bas. La probabilité de lire un 1 à chaque cycle est proportionnelle à la largeur d'impulsion. Un filtre passe-bas IIR facile à mettre en œuvre est:

double acc=0.5;
const double k=0.01;
for(;;) {
  bool x=GPIO.read();
  acc+=k*(x?1:0-acc);
}

Lorsque k diminue, la résolution s'améliore mais la bande passante diminue.

wdg
la source
0

Bien que ma réponse ne provienne pas des broches, vous pouvez utiliser quelque chose basé sur un oscilloscope de carte son pour lire une entrée pulsée.

Les gens utilisent les cartes son dans les PC de bureau depuis des années pour créer des oscilloscopes. Il semble qu'avec une carte son interne moderne, vous pouvez obtenir des résultats utilisables jusqu'à 10 kHz. Avec une carte son connectée par USB Raspberry Pi, votre fréquence maximale peut être inférieure.

Voici un exemple d'un projet d'oscilloscope de carte son pour Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html

pierce.jason
la source
0

Ce script python que j'ai écrit fonctionne très bien pour moi pour lire les signaux PWM d'un récepteur RC. Les signaux PWM haute fréquence ne fonctionneront évidemment pas comme cela a déjà été souligné.

J'ai directement connecté les dix broches de sortie de signal du récepteur RC aux broches Raspberry GPIO. Le récepteur est alimenté par les broches + 5V et GND du RPI.

J'ai simplifié le script car il fait beaucoup d'autres choses, si vous trouvez des erreurs ou des restes, faites le moi savoir

import RPi.GPIO as GPIO
import time
import numpy as np
inPINS = [2,3,4,14,15,18,17,27,22,23]
smoothingWindowLength=4

def getTimex():
    return time.time()

GPIO.setup(inPINS, GPIO.IN)
upTimes = [[0] for i in range(len(inPINS))]
downTimes = [[0] for i in range(len(inPINS))]
deltaTimes = [[0] for i in range(len(inPINS))]

def my_callback1(channel):
  i = inPINS.index(channel)
  v = GPIO.input(inPINS[i])
  #GPIO.output(outPINS[0], v) # mirror input state to output state directly (forward servo value only) - don't set PWM then for this pin
  if (v==0):
    downTimes[i].append(getTimex())
    if len(downTimes[i])>smoothingWindowLength: del downTimes[i][0]
  else:
    upTimes[i].append(getTimex())
    if len(upTimes[i])>smoothingWindowLength: del upTimes[i][0]
  deltaTimes[i].append( (downTimes[i][-1]-upTimes[i][-2])/(upTimes[i][-1]-downTimes[i][-1]) )
  if len(deltaTimes[i])>smoothingWindowLength: del deltaTimes[i][0]

GPIO.add_event_detect(inPINS[0], GPIO.BOTH, callback=my_callback1)
GPIO.add_event_detect(inPINS[1], GPIO.BOTH, callback=my_callback1)

try:
  while True:
    ovl = deltaTimes[0][-smoothingWindowLength:] # output first pin PWM
    ov = sorted(ovl)[len(ovl) // 2] #ov = np.mean(ovl)
    print ov
    time.sleep(0.1)
except KeyboardInterrupt:
  GPIO.cleanup()
user2707001
la source
0

Il est très possible et relativement facile de lire les entrées PWM sur Raspberry Pi en utilisant la bibliothèque pigpio C. Si vous voulez de bonnes performances, je recommande d'utiliser C, pas Python. J'ai fourni un court exemple de code ci-dessous. Contrairement à ce que certains disent, cela a d'excellentes performances de synchronisation et une gigue assez faible. Les lectures sont constamment à moins de 5 us sur mon RPi 3 B et il peut mesurer des impulsions aussi courtes que 5 us. Notez que le code fourni n'est qu'une preuve de concept, il ne gère pas correctement l'absence d'impulsions (rapport cyclique 0% / 100%) ou le bouclage `` tick '' qui se produit toutes les 72 minutes. Le programme fonctionne très bien en mode utilisateur, mais pour une meilleure résistance aux problèmes de synchronisation, exécutez votre programme à un niveau négatif agréable comme ceci: sudo nice -n -20 ./program

Voir la documentation de pigpio sur: http://abyz.me.uk/rpi/pigpio/pdif2.html

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include "pigpiod_if2.h"

static uint32_t rise_tick = 0;    // Pulse rise time tick value
static uint32_t pulse_width = 0;  // Last measured pulse width (us)

// Callback function for measuring PWM input
void pwm_cbfunc(int pi, unsigned user_gpio, unsigned level, uint32_t tick) {
    if (level == 1) {  // rising edge
        rise_tick = tick;
    }
    else if (level == 0) {  // falling edge
        pulse_width = tick - rise_tick;  // TODO: Handle 72 min wrap-around
    }
}

int main(int argc, char **argv)
{
    const unsigned int pwm_in = 23; // GPIO Pin # for PWM in, change as reqd

    int pi = pigpio_start(0, 0);
    if (pi < 0) {
        fprintf(stderr, "pigpio initialization failed (%d)\n", pi);
        return pi;
    }

    // Set up callback for PWM input 
    callback(pi, pwm_in, EITHER_EDGE, pwm_cbfunc);

    while (true) {
        printf("PWM pulse width: %u\n", pulse_width);
        usleep(500000);
    }
}
Georgie
la source
-3

Solution facile avec une grande précision:

L'utilisation d'un Arduino comme esclave iic ou appareil UART semble fonctionner parfaitement bien. Le microcontrôleur est capable de lire les informations via la méthode pulseIn.

Pour des informations détaillées: https://www.youtube.com/watch?v=ncBDvcbY1l4

Simon
la source
Bienvenue sur Raspberry Pi! Bien que cela puisse théoriquement répondre à la question, il serait préférable d'inclure ici les parties essentielles de la réponse et de fournir le lien de référence. Nous essayons une nouvelle politique en ce qui concerne les réponses de lien sans information uniquement ici . Si ce message n'est pas modifié pour contenir des informations pouvant servir de réponse, même minime, il sera converti en Wiki communautaire en 48 heures pour simplifier sa correction par la communauté.
Ghanima