ШИМ вход в Raspberry Pi


10

Есть ли способ прочитать сигнал ШИМ с контактов на Raspberry Pi?

Я попытался прибегая к помощи, но я нашел только PWM выход , а не вход .

Ответы:


4

Краткий ответ: Вы НЕ МОЖЕТЕ достоверно читать ШИМ на Raspberry Pi.

Чтение ШИМ требует микросекундной точности (если вы не читаете очень-очень медленный ШИМ), и это недоступно в Raspberry Pi для пользовательского программного обеспечения без работы с модулями ядра.

Самый простой способ перехватить ШИМ - это получить любой дешевый (менее $ 0,5) микроконтроллер с последовательным выходом или выходом I 2 C, подключить его к Raspberry Pi и считать фактические значения с микроконтроллера. Это будет работать очень надежно и достаточно точно.


1
Есть идеи, где взять такую ​​микросхему?
Pepijn

@Pepijn то, что вы ищете, это аналого-цифровой преобразователь (АЦП). Очень распространенным, который я очень часто использую, является 8-канальный 10-разрядный модуль MCP3008 , а другой, который у меня постоянно находится на тестовом модуле Pi для моего программного обеспечения Perl, - это 4-канальный 16-разрядный модуль ADS1115 . Последнему нужно немного паять, первому - нет. Есть много примеров кода, доступных для использования обоих этих модулей (C, Python, Perl и т. Д.), Поэтому, если вы не хотите / не можете написать свой собственный, это должно быть тривиально.
Stevieb

Подойдет любой простой микроконтроллер. Я использовал продукты Microchip для такого рода вещей. Появление Arduino снова принесло популярность чипы AVR. Теперь я просто использую небольшую коммутационную плату с микроконтроллером и всем необходимым для жизнеобеспечения чипом. Мой любимый сериал Teensy 3.x.
NomadMaker

3

Я могу сделать довольно точное измерение ширины импульса, используя библиотеку piGpio C: http://abyz.me.uk/rpi/pigpio/index.html

Эта библиотека позволяет вам установить функцию обратного вызова, которая будет запускаться при любом переходе ребра на выводе gpio, и давать вам метку времени микросекундного уровня для каждого перехода. Не думаю, что вы можете рассчитывать на точность микросекунды - но мои тесты показывают, что точность составляет не менее +/- 10us, а может и лучше.

Гораздо лучше, чем запускать петлю занятых, опрашивая gpio для изменения уровня самостоятельно.


+1 Может быть стоит отметить, что точность может варьироваться в зависимости от загрузки процессора (особенно одноядерных), но в остальном хороший ответ. :)
Jacobm001

Спасибо Stevec, этот ответ намного лучше, чем сказать, что «это невозможно сделать». Смотрите мой отдельный ответ для получения дополнительной информации, включая фактический код (это очень короткий).
Джорджи

2

Это интересный вопрос, и вы правильно сказали, что поиск в Google не дает очевидного решения! (Я скучаю по дням, когда Google мог ответить на все, что я хотел знать, для моего образования / заданий в течение нескольких секунд.)

Я предполагаю, что вы понимаете принципы ШИМ . Поэтому я не буду вдаваться в это. Тем не менее, я считаю, что теоретически вы могли бы прочитать значение ШИМ на обычном цифровом входном выводе с некоторым умным кодированием.

Я признаю, что сам не пробовал этого, но вы должны быть в состоянии измерить время, когда вывод высок и время, за которое он низок (дает вам ваши показания ШИМ), а затем использовать любую математическую формулу, предоставленную поставщиком сенсора. чтобы преобразовать это в фактическое чтение.

Этот метод работает для меня по аналогичной проблеме, где мне нужно было прочитать длину импульса от ультразвукового модуля, а затем преобразовать его в расстояние. Проблемы, которые я могу предусмотреть, включают в себя обеспечение надежных показаний!

Если вы думаете, что это поможет и хотите увидеть код, который я использовал для ультразвукового модуля, просто скажите об этом, и я скопирую его, когда вернусь домой.

Я начал копировать код, но по какой-то причине веб-сайт позволяет мне копировать его только в небольшой раздел за раз (и я слишком ленив, чтобы вытащить мой пи из гаража), поэтому вот ссылка на него. игнорируйте большинство функций внизу, так как они связаны с использованием модуля в качестве датчика приближения. http://pibot.webnode.com/products/ultrasonic-range-sensor/


Было бы хорошо увидеть код, так что я могу получить базу для запуска собственного кода, если вы можете вставить сюда, я буду очень благодарен ^^
Caio Keto

Проблема с этим предположением заключается в том, что ядро ​​Linux не дает достаточно времени для чтения типичных рабочих циклов RC PWM (которые обычно составляют 1000-2000 микросекунд каждые 16 миллисекунд) с достаточной точностью. Если бы мы могли установить обработчик прерываний для смены выводов GPIO и зафиксировать временную метку при переходах высокого / низкого уровня в модуле ядра, то это могло бы быть полезным решением.
Джон Уотт

1

Длинный ответ: вы действительно можете! (ну с небольшой помощью от наших друзей резистор и конденсатор)

Вы можете преобразовать выход ШИМ в аналоговый уровень напряжения (ЦАП) и прочитать его с помощью контакта АЦП на вашем Raspberry Pi.

Вам нужен резистор 4к7 и конденсатор 0,1 мкФ:

схематический

смоделировать эту схему - схема, созданная с использованием CircuitLab

Простой фильтр низких частот RC, приведенный выше, преобразует сигнал ШИМ в напряжение, пропорциональное рабочему циклу, которое может быть считано вашим Raspberry Pi в качестве аналогового значения.


4
Вывод АЦП? И что это будет?
Ганима

@Ghanima Что ж, новый драйвер Microsoft Lightning находится в разработке, но он служит для этой цели довольно хорошо (он задокументирован на их страницах). Для того, что я нашел для BCM2837, у него может быть аппаратный АЦП, который находится на GPIO0 (к сожалению, этот не связан ни с одним выводом заголовка) .. по крайней мере, они связали аппаратные каналы ШИМ
Quest

0

Если вас устраивает медленный ответ, вы можете прочитать быстрый PWM с помощью недостаточной выборки. Просто прочитайте GPIO в цикле и примените фильтр нижних частот. Вероятность считывания 1 в каждом цикле пропорциональна ширине импульса. Простой в применении фильтр низких частот IIR:

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

С уменьшением k разрешение улучшается, но ширина полосы уменьшается.


0

Хотя мой ответ не из выводов, вы могли бы использовать что-то на основе осциллографа звуковой карты, чтобы прочитать импульсный вход.

Люди годами используют звуковые карты в настольных ПК для создания осциллографов. Похоже, что с современной внутренней звуковой картой вы можете получить полезные результаты до 10 кГц. При использовании звуковой карты Raspberry Pi USB, ваша максимальная частота может быть ниже.

Вот пример одного проекта осциллографа звуковой карты для Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html


0

Этот скрипт на python, который я написал, отлично подходит для чтения сигналов ШИМ RC-ресивера. Высокочастотные ШИМ-сигналы, очевидно, не будут работать, как уже указывалось.

Я непосредственно подключил десять выводов сигнала RC-приемника к выводам Raspberry GPIO. Приемник питается от контактов + 5 В и GND от RPI.

Я упростил скрипт, так как он делает много других вещей, если вы обнаружите какие-либо ошибки или остатки, дайте мне знать

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()

0

Очень легко и относительно легко прочитать входные данные ШИМ на Raspberry Pi, используя библиотеку pigpio C. Если вы хотите хорошую производительность, я рекомендую использовать C, а не Python. Я предоставил небольшой пример кода ниже. Вопреки тому, что некоторые люди говорят, это имеет отличные характеристики синхронизации и довольно низкий уровень джиттера. Показания на моем RPi 3 B постоянно находятся в пределах 5 мкс, и он может измерять импульсы с точностью до 5 мкс. Обратите внимание, что предоставленный код является только концептуальным подтверждением, он не обрабатывает должным образом отсутствие импульсов (0% / 100% рабочего цикла) или «тиковый» переход, который происходит каждые 72 минуты. Программа отлично работает в пользовательском режиме, но для лучшей устойчивости к временным сбоям, запустите вашу программу на отрицательном хорошем уровне, например: sudo nice -n -20 ./program

Смотрите документацию по pigpio по адресу: 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);
    }
}

-3

Простое решение с высокой точностью:

Использование Arduino в качестве iic slave или UART-устройства, кажется, прекрасно работает. Микроконтроллер способен считывать информацию с помощью метода pulseIn.

Для получения подробной информации: https://www.youtube.com/watch?v=ncBDvcbY1l4


Добро пожаловать в Raspberry Pi! Хотя это может теоретически ответить на вопрос, было бы предпочтительным включить сюда основные части ответа и предоставить ссылку для справки. Мы пробуем новую политику в отношении ответов без информации только здесь . Если это сообщение не будет отредактировано и содержать информацию, которая может быть ответом, пусть и минимальным, через 48 часов, оно будет преобразовано в вики сообщества, чтобы упростить его исправление сообществом.
Ганима
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.