如何消除从无线电接收器读取的 PWM 中的噪声?

How to remove noise from PWM read from a radio receiver?

我正在使用 FlySky 的遥控器。对于我的机器人项目,我想从 arduino 上的接收器读取 PWM。我遇到了 2 个选项:

我不能使用 pulseIn() 的第一个选项,因为我希望我的机器人在接收器信号没有到来时继续操作(Tx 不可用等)所以我使用 ISR

最可靠的来源:YouTube 上的 Mr. Brookings 频道。

这是我所做的(只有 1 个轴需要的部分):

// [R] where R is defined as 0 => [R] == [0]

volatile long CH[4];   //4 pwms to read so array of 4
float IN[3]={0,0,0};   // throttle is directly written
unsigned long timer[4],curr_time; 
byte last[4];   

void setup(){
    PCICR |= (1 << PCIE0);  
    PCMSK0 |= (1 << PCINT0);
    PCMSK0 |= (1 << PCINT1);
    PCMSK0 |= (1 << PCINT2);
    PCMSK0 |= (1 << PCINT3);

    /* There is some more code here */

    
    Serial.begin(115200);
}
void loop(){

    /* There is some more code here */
    IN[R] = ((CH[ROLL]  - (1500 + R_TRIM))/11.0);  // eg.: (1200 - (1500 + 8))/11.0 = -28 (interpreted as setpoint of -28° by the robot) 
    Serial.println(IN[R]);
}

ISR(PCINT0_vect){

    curr_time = micros();
    //channel 1 roll
    if(PINB & B00000001){
        if(last[ROLL] == 0){
            last[ROLL] = 1;
            timer[ROLL] = curr_time;
        }
    }
    else if(last[ROLL] == 1){
        last[ROLL] = 0;
        CH[ROLL] = ((curr_time - timer[ROLL]));
    }
}

我居然能读懂PWM。但是机器人在给定的设定点不断地在其控制中显示出随机抽动。我设法追查原因,发现 PWM 被噪音疯狂缠绕。它不像它应该的那样稳定——稳定。我有一个用于分析的 MATLAB 图:

信号(IN[R]):

特写(当Tx摇杆在中间w/o移动时):

有这样的尖峰信号叠加到控制信号上,最终使我的机器人抽搐。我尝试了一些过滤技术,例如 'moving average' 和“一阶和二阶指数滤波器”。还检查了它是否是由于供电引起的 - 尝试将电容器或铁芯放在电源线上但徒劳无功。我可以弄清楚如何删除它们作为它们的一些限制:

我希望得到一些指导!

无法从中判断输入是否有噪声,或者您的代码是否错误地读取了 PWM,是否发生了其他问题,例如线路上的外部噪声、Arduino 的时钟抖动或其他中断需要时间。另请注意,Arduino Uno 上的 micros() 只有 4µs 的分辨率,而不是 1µs。

您应该检查输入的抖动和噪声,并尝试不受其他中断影响的快速代码。

获取 PWM 脉冲宽度的一种相当简单快速的方法是这样的,最好不要使用任何其他使用中断的方法:

volatile int pwmPulseWidth = 0;
volatile unsigned long int previousTime = 0;
 
void setup() {
  attachInterrupt(0, rising, RISING);
}
 
void loop() {
  // pwmPulseWidth is available here.
}
 
void rising() {
  attachInterrupt(0, falling, FALLING);
  previousTime = micros();
}
 
void falling() {
  attachInterrupt(0, rising, RISING);
  pwmPulseWidth = micros() - previousTime;
}

未经测试,但它应该会给你一个想法。这将 return PWM 脉冲的宽度。当然,还有其他方法可以做到这一点,比如在捕获模式下使用定时器。

如果您愿意,知道 PWM 频率和 PWM 脉冲宽度就足以重建 PWM 信号。