Respostas:
A resposta curta: você NÃO PODE ler o PWM de maneira confiável no Raspberry Pi.
A leitura do PWM requer precisão de microssegundos (a menos que você esteja lendo um PWM muito, muito lento), e isso não está disponível no Raspberry Pi para software da terra do usuário sem mexer nos módulos do kernel.
A maneira mais fácil de capturar o PWM seria obter um microcontrolador barato (<US $ 0,5) com saída serial ou I 2 C e conectá-lo ao seu Raspberry Pi e ler os valores reais do microcontrolador. Isso funcionará com muita confiabilidade e é bastante preciso.
Posso fazer medições de largura de pulso bastante precisas usando a biblioteca piGpio C: http://abyz.me.uk/rpi/pigpio/index.html
Essa biblioteca permite instalar uma função de retorno de chamada que será acionada em qualquer transição de borda em um pino gpio e fornece um registro de data e hora em nível de microssegundo para cada transição. Não pense que você pode contar com isso para precisão de microssegundos - mas meus testes sugerem que a precisão é pelo menos +/- 10us, talvez melhor.
Muito melhor do que executar um loop ocupado pesquisando um gpio para alterar o nível.
Esta é uma pergunta interessante e que você está correto ao dizer que a Pesquisa do Google não fornece uma solução óbvia! (Sinto falta dos dias em que o Google podia responder a qualquer coisa que eu queria saber sobre meus estudos / tarefas em segundos.)
Suponho que você entenda os princípios do PWM . Portanto, não vou entrar nisso. No entanto, acredito que você poderia, em teoria, ler um valor PWM em um pino de entrada digital regular com alguma codificação inteligente.
Admito que não tentei isso sozinho, mas você deve medir o tempo em que o pino está alto e o tempo em que ele é baixo (fornecendo sua leitura do PWM) e depois usar a fórmula matemática fornecida pelo fornecedor do sensor para converter isso na leitura real.
Esse método funciona para mim em um problema semelhante, onde eu precisava ler o comprimento do pulso de um módulo ultrassônico e depois convertê-lo para a distância. Os problemas que posso imaginar envolvem garantir leituras confiáveis!
Se você acha que vai ajudar e deseja ver o código que usei para o módulo ultrassônico, basta dizer e copiarei quando chegar em casa.
Comecei a copiar o código, mas por algum motivo o site só me permite copiá-lo uma pequena seção de cada vez (e estou com preguiça de tirar meu pi da garagem), então aqui está o link para ele. ignore a maioria das funções na parte inferior, pois elas estão relacionadas ao uso do módulo como sensor de proximidade. http://pibot.webnode.com/products/ultrasonic-range-sensor/
A resposta longa: você realmente pode! (bem, com uma pequena ajuda dos nossos amigos resistor e capacitor)
Você pode converter uma saída PWM para um nível de tensão analógica (DAC) e lê-la com o pino ADC no seu raspberry pi.
O que você precisa é de um resistor de 4k7 e capacitor de 0,1uF:
simular este circuito - esquemático criado usando o CircuitLab
O simples filtro passa-baixa RC acima converte o sinal PWM em uma tensão proporcional ao ciclo de serviço que pode ser lido pelo seu raspberry pi como um valor analógico.
Se você estiver satisfeito com uma resposta lenta, poderá ler um PWM rápido subamostrando. Basta ler o GPIO em um loop e aplicar um filtro passa-baixo. A probabilidade de ler 1 a cada ciclo é proporcional à largura do pulso. Um filtro passa-baixa IIR fácil de implementar é:
double acc=0.5;
const double k=0.01;
for(;;) {
bool x=GPIO.read();
acc+=k*(x?1:0-acc);
}
À medida que k diminui, a resolução melhora, mas a largura de banda diminui.
Embora minha resposta não seja dos pinos, você pode usar algo baseado no osciloscópio da placa de som para ler uma entrada pulsada.
As pessoas usam placas de som em computadores desktop há anos para criar osciloscópios. Parece que, com uma moderna placa de som interna, você pode obter resultados úteis até 10kHz. Com uma placa de som conectada ao Raspberry Pi USB, sua frequência máxima pode ser menor.
Aqui está um exemplo de um projeto do osciloscópio da placa de som para Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html
Esse script python que escrevi funciona bem para mim na leitura de sinais PWM de um receptor RC. Os sinais PWM de alta frequência obviamente não funcionarão como já foi apontado.
Conectei diretamente os dez pinos de saída de sinal do receptor RC aos pinos Raspberry GPIO. O receptor é alimentado pelos pinos + 5V e GND do RPI.
Simplifiquei o script, pois ele faz muitas outras coisas. Se você encontrar algum erro ou sobra, me avise
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()
É muito possível e relativamente fácil ler entradas PWM no Raspberry Pi usando a biblioteca pigpio C. Se você quer um bom desempenho, recomendo usar C, não Python. Forneci alguns exemplos de código abaixo. Ao contrário do que algumas pessoas dizem, isso tem excelente desempenho de temporização e instabilidade bastante baixa. As leituras são consistentemente dentro de 5 nós no meu RPi 3 B e podem medir pulsos tão curtos quanto 5 nós. Observe que o código fornecido é apenas uma prova de conceito, ele não lida adequadamente com a ausência de pulsos (ciclo de trabalho de 0% / 100%) ou a envolvente 'tick' que ocorre a cada 72 minutos. O programa funciona muito bem no modo de usuário, mas para obter melhor resistência a falhas de tempo, execute o programa em um nível agradável negativo como este: sudo nice -n -20 ./program
Veja os documentos do pigpio em: 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);
}
}
Solução fácil com alta precisão:
Usar um Arduino como escravo iic ou dispositivo UART parece funcionar perfeitamente. O microcontolador é capaz de ler as informações pelo método pulseIn.
Para obter informações detalhadas: https://www.youtube.com/watch?v=ncBDvcbY1l4