如何消除从无线电接收器读取的 PWM 中的噪声?
How to remove noise from PWM read from a radio receiver?
我正在使用 FlySky 的遥控器。对于我的机器人项目,我想从 arduino 上的接收器读取 PWM。我遇到了 2 个选项:
pulseIn()
arduino 函数
ISR(PCINTx_vect)
(中断)
我不能使用 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' 和“一阶和二阶指数滤波器”。还检查了它是否是由于供电引起的 - 尝试将电容器或铁芯放在电源线上但徒劳无功。我可以弄清楚如何删除它们作为它们的一些限制:
- 平台是 Arduino Uno(在繁重的计算中速度较慢)
- 控制回路不得低于 100Hz(目前它在 4 轴上的 108Hz 指数滤波器将它带到
~85Hz)
我希望得到一些指导!
无法从中判断输入是否有噪声,或者您的代码是否错误地读取了 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 信号。
我正在使用 FlySky 的遥控器。对于我的机器人项目,我想从 arduino 上的接收器读取 PWM。我遇到了 2 个选项:
pulseIn()
arduino 函数ISR(PCINTx_vect)
(中断)
我不能使用 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' 和“一阶和二阶指数滤波器”。还检查了它是否是由于供电引起的 - 尝试将电容器或铁芯放在电源线上但徒劳无功。我可以弄清楚如何删除它们作为它们的一些限制:
- 平台是 Arduino Uno(在繁重的计算中速度较慢)
- 控制回路不得低于 100Hz(目前它在 4 轴上的 108Hz 指数滤波器将它带到 ~85Hz)
我希望得到一些指导!
无法从中判断输入是否有噪声,或者您的代码是否错误地读取了 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 信号。