如果我们做了一个小的创意作品,而它需要远距离的无线控制,比如遥控车、遥控航模、遥控船等,这时候我们必定会认真考虑如何实现无线控制这个问题。蓝牙、WiFi、ZigBee、NRF、HC-12等都可以,但是也都不同程度上存在一定的弊端,而且使用以上几种方式都得另外制作一个遥控器实体,既然如此那么为什么不考虑直接使用成熟的商业遥控器呢?比如便宜好用的天地飞、高端的Futaba等。它们自身就是一个成熟的遥控器,有两个遥杆,至少四路信号输出,千米级的稳定传输,一切看来似乎都是这么美好!但问题是如何接收到并解析出它们所发出的信号呢?下面就来解决一下这个问题!
首先得了解一下遥控器的基本常识,就是遥控器和接收机之间有自己的通信协议,这个协议各个遥控器厂商都有自己的一套标准而且之间互不兼容,但是接收机输出的信号却有较为统一的标准,常见的有PWM、PPM、各种.bus(比如Futaba的s.bus),这里面最简单的自然就是PWM了,接收机的每个引脚单独输出一路PWM信号,发送给执行器或者飞控,在固定翼航模上面通常都是直接发给执行器(舵机、电调等),实现对它们的直接控制。
PWM是一种高低电平信号,通过高电平的持续时间(脉冲宽度)来传输信息,在遥控器上这个脉冲宽度通常大约是1000-2000毫秒,电调和舵机接收的信号范围通常也是1000-2000毫秒。那么如何使用Arduino来获取到这个脉冲宽度呢?这就要用到Arduino的外部中断了(当然单片机系统都有中断功能),通过两次中断事件发生的时间间隔来获取脉冲宽度。解决了这个问题,那么就可以使用遥控器去控制航模、车模、船模了!(令人愉快的事情又多了一件!)
下面是Arduino MEGA获取天地飞7遥控器信号并发给电调和舵机来控制航模的一段代码:
#include <Servo.h>
#define forward_back_pin 19 //2通道
#define left_right_pin 20 //1通道
#define power_pin 21 //3通道
//中断引脚编号
#define forward_back_int_pin 4
#define left_right_int_pin 3
#define pow_int_pin 2
//4路舵机和1路电调的引脚
#define forward_back_servo_pin1 8
#define forward_back_servo_pin2 9
#define left_right_servo_pin1 10
#define left_right_servo_pin2 11
#define pow_servo_pin 12
Servo forward_back_servo1;
Servo forward_back_servo2;
Servo left_right_servo1;
Servo left_right_servo2;
Servo pow_servo;
int power_val=0,forward_back_val=0,left_right_val=0;
unsigned long timer1=0,timer2=0,timer3=0;
void setup() {
Serial.begin(115200);
pinMode(power_pin,INPUT);
pinMode(left_right_pin,INPUT);
pinMode(forward_back_pin,INPUT);
//注册中断函数
attachInterrupt(pow_int_pin,power,CHANGE);
attachInterrupt(forward_back_int_pin,forward_back,CHANGE);
attachInterrupt(left_right_int_pin,left_right,CHANGE);
pow_servo.attach(pow_servo_pin,1000,2000);
forward_back_servo1.attach(forward_back_servo_pin1,1000,2000);
forward_back_servo2.attach(forward_back_servo_pin2,1000,2000);
left_right_servo1.attach(left_right_servo_pin1,1000,2000);
left_right_servo2.attach(left_right_servo_pin2,1000,2000);
}
void loop() {
// Serial.println("!!!!!!!!!!!!!!!!!" );
// Serial.println("Pulse Value Is : ");
// Serial.print("power:");
// Serial.println(power_val);
// Serial.print("left_right:");
// Serial.println(left_right_val);
// Serial.print("forward_back:");
// Serial.println(forward_back_val);
// Serial.println("!!!!!!!!!!!!!!!!!" );
// delay(1000);
pow_servo.write(power_val);
turn();
fly();
}
void turn(){
left_right_servo1.write(left_right_val);
left_right_servo2.write(left_right_val);
}
void fly(){
forward_back_servo1.write(3000-forward_back_val);
forward_back_servo2.write(forward_back_val);
}
//油门信号中断函数
void power(){
if(digitalRead(power_pin)==HIGH){
timer1=micros();
}
else{
power_val=micros()-timer1;
}
}
//前后舵量信号中断函数
void forward_back(){
if(digitalRead(forward_back_pin)==HIGH){
timer2=micros();
}
else{
forward_back_val=micros()-timer2;
}
}
//左右多量信号中断函数
void left_right(){
if(digitalRead(left_right_pin)==HIGH){
timer3=micros();
}
else{
left_right_val=micros()-timer3;
}
}