Ответы:
Краткий ответ: Вы НЕ МОЖЕТЕ достоверно читать ШИМ на Raspberry Pi.
Чтение ШИМ требует микросекундной точности (если вы не читаете очень-очень медленный ШИМ), и это недоступно в Raspberry Pi для пользовательского программного обеспечения без работы с модулями ядра.
Самый простой способ перехватить ШИМ - это получить любой дешевый (менее $ 0,5) микроконтроллер с последовательным выходом или выходом I 2 C, подключить его к Raspberry Pi и считать фактические значения с микроконтроллера. Это будет работать очень надежно и достаточно точно.
Я могу сделать довольно точное измерение ширины импульса, используя библиотеку piGpio C: http://abyz.me.uk/rpi/pigpio/index.html
Эта библиотека позволяет вам установить функцию обратного вызова, которая будет запускаться при любом переходе ребра на выводе gpio, и давать вам метку времени микросекундного уровня для каждого перехода. Не думаю, что вы можете рассчитывать на точность микросекунды - но мои тесты показывают, что точность составляет не менее +/- 10us, а может и лучше.
Гораздо лучше, чем запускать петлю занятых, опрашивая gpio для изменения уровня самостоятельно.
Это интересный вопрос, и вы правильно сказали, что поиск в Google не дает очевидного решения! (Я скучаю по дням, когда Google мог ответить на все, что я хотел знать, для моего образования / заданий в течение нескольких секунд.)
Я предполагаю, что вы понимаете принципы ШИМ . Поэтому я не буду вдаваться в это. Тем не менее, я считаю, что теоретически вы могли бы прочитать значение ШИМ на обычном цифровом входном выводе с некоторым умным кодированием.
Я признаю, что сам не пробовал этого, но вы должны быть в состоянии измерить время, когда вывод высок и время, за которое он низок (дает вам ваши показания ШИМ), а затем использовать любую математическую формулу, предоставленную поставщиком сенсора. чтобы преобразовать это в фактическое чтение.
Этот метод работает для меня по аналогичной проблеме, где мне нужно было прочитать длину импульса от ультразвукового модуля, а затем преобразовать его в расстояние. Проблемы, которые я могу предусмотреть, включают в себя обеспечение надежных показаний!
Если вы думаете, что это поможет и хотите увидеть код, который я использовал для ультразвукового модуля, просто скажите об этом, и я скопирую его, когда вернусь домой.
Я начал копировать код, но по какой-то причине веб-сайт позволяет мне копировать его только в небольшой раздел за раз (и я слишком ленив, чтобы вытащить мой пи из гаража), поэтому вот ссылка на него. игнорируйте большинство функций внизу, так как они связаны с использованием модуля в качестве датчика приближения. http://pibot.webnode.com/products/ultrasonic-range-sensor/
Длинный ответ: вы действительно можете! (ну с небольшой помощью от наших друзей резистор и конденсатор)
Вы можете преобразовать выход ШИМ в аналоговый уровень напряжения (ЦАП) и прочитать его с помощью контакта АЦП на вашем Raspberry Pi.
Вам нужен резистор 4к7 и конденсатор 0,1 мкФ:
смоделировать эту схему - схема, созданная с использованием CircuitLab
Простой фильтр низких частот RC, приведенный выше, преобразует сигнал ШИМ в напряжение, пропорциональное рабочему циклу, которое может быть считано вашим Raspberry Pi в качестве аналогового значения.
Если вас устраивает медленный ответ, вы можете прочитать быстрый 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 разрешение улучшается, но ширина полосы уменьшается.
Хотя мой ответ не из выводов, вы могли бы использовать что-то на основе осциллографа звуковой карты, чтобы прочитать импульсный вход.
Люди годами используют звуковые карты в настольных ПК для создания осциллографов. Похоже, что с современной внутренней звуковой картой вы можете получить полезные результаты до 10 кГц. При использовании звуковой карты Raspberry Pi USB, ваша максимальная частота может быть ниже.
Вот пример одного проекта осциллографа звуковой карты для Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html
Этот скрипт на 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()
Очень легко и относительно легко прочитать входные данные ШИМ на 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);
}
}
Простое решение с высокой точностью:
Использование Arduino в качестве iic slave или UART-устройства, кажется, прекрасно работает. Микроконтроллер способен считывать информацию с помощью метода pulseIn.
Для получения подробной информации: https://www.youtube.com/watch?v=ncBDvcbY1l4