Entrada PWM no Raspberry Pi

10

Existe uma maneira de ler um sinal PWM dos pinos do Raspberry Pi?

Tentei pesquisar no Google, mas só encontrei saída PWM , e não entrada .

Caio Keto
fonte

Respostas:

4

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.

lenik
fonte
11
Alguma idéia de onde conseguir esse CI?
Pepijn 27/05
@Pepijn o que você procura é um conversor analógico-digital (ADC). Um muito comum que eu uso com muita freqüência é o MCP3008 de 8 canais, unidade de 10 bits, e outro que permanentemente tenho em minha unidade testando Pi para o meu software Perl é o ADS1115 de 4 canais e 16 bits. O último precisa de um pouco de trabalho de solda, o primeiro não. Existem muitos exemplos de código disponíveis para usar essas duas unidades (C, Python, Perl, etc.), portanto, se você não quiser / não puder escrever por conta própria, deve ser trivial continuar.
22417 stevieb
Qualquer microcontrolador simples serve. Eu costumava usar produtos Microchip para esse tipo de coisa. O advento do Arduino trouxe os chips AVR novamente à popularidade. Agora, apenas uso uma pequena placa de circuito impresso contendo um microcontrolador e qualquer suporte de vida que o chip precise. O meu favorito é a série Teensy 3.x.
NomadMaker 7/04
3

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.

stevec
fonte
+1 Pode ser interessante notar que a precisão pode variar um pouco com base na carga da CPU (especialmente os núcleos únicos), mas de outra forma uma boa resposta. :)
Jacobm001
Obrigado stevec, esta resposta é muito melhor do que dizer "não pode ser feito". Veja minha resposta separada para obter mais informações, incluindo o código real (é muito curto).
Georgie
2

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/

D Mason
fonte
Isso vai ser bom para ver o código, para que eu possa ter uma base para começar o meu próprio código, se você pode colar aqui eu vou ser muito grata ^^
Caio Keto
O problema com essa sugestão é que o kernel do Linux não oferece tempo suficiente para a leitura dos ciclos de tarefas RC PWM típicos (que geralmente são de 1000 a 2000 microssegundos a cada 16 milissegundos) com precisão suficiente. Se pudéssemos instalar um manipulador de interrupção para uma mudança de pino GPIO e capturar o registro de data e hora em transições alto / baixo, em um módulo do kernel, essa pode ser uma solução útil.
precisa saber é o seguinte
1

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:

esquemático

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.

Busca
fonte
4
O pino ADC? E qual seria?
Ghanima
@Ghanima Bem, o novo driver Microsoft Lightning está em desenvolvimento, mas atende a esse propósito muito bem (está documentado em suas páginas). Para o que eu encontrei para BCM2837 pode ter um ADC de hardware que está em GPIO0 (infelizmente este não está ligado a qualquer pino cabeçalho) .. pelo menos eles ligados canais PWM hardware
Missão
0

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.

wdg
fonte
0

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

pierce.jason
fonte
0

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()
user2707001
fonte
0

É 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);
    }
}
Georgie
fonte
-3

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

Simon
fonte
Bem-vindo ao Raspberry Pi! Embora isso possa teoricamente responder à pergunta, seria preferível incluir aqui as partes essenciais da resposta e fornecer o link para referência. Estamos tentando uma nova política em relação às respostas somente para links sem informação aqui . Se esta postagem não for editada para conter informações que possam ser uma resposta, por mínima que seja, em 48 horas, ela será convertida em Wiki da Comunidade para simplificar a correção pela comunidade.
Ghanima