Réponses:
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.
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.
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/
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:
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.
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.
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
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()
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);
}
}
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