玩转树莓派

    返回首页    发表留言
本文作者:李德强
          第七节 遥控器读数
 
 

       一、简单认识遥控器

       接下来我们要了解的是摇控器,你如果对摇控器有一定了解的话可能听说过“日本手”和“美国手”这两种不同的摇控器。其实它们并没有什么本质差别。假设我们的四轴已经可以成功的飞行,我们需要摇控器上的一个控制杆可以控制四个电机的整体转数,也就是人们常说的“油门”。当然,油门这个词用在四轴上可能不太贴切,它的作用就是控制电机转数,可快,可慢,而所谓的“日本手”摇控器是油门在右侧,“美国手”摇控器的油门则在左侧:
 

 

 

 


        关于选择日本手还是美国手,我们还建议是根据你自己的习惯(其实没有什么区别)。另外摇控器上还有很多其它的功能控制旋钮,你可能被说明书搞的头晕脑涨,不过你完全不用担心。我们的四轴只用摇控器的3个通道,也就是“前/后”、“左/右”、“上、下”。摇控器其实是两个设备,包括一个发射器和一个接收机,接收机就是我们要接在树莓派上的。发射器就是我们手里拿的摇控器。我们不管用的是什么日本手还是美国手,先来看看它的4个通道:
 

 


        也就是说,我们只用到3个通道来控制四轴,“前/后(俯仰)”、“左/右(横滚)”、“上、下(油门)”,而对于“航向”通道我们暂时不做处理。而用于这3个功能的通道我们可以自己定义,你想让哪个通道来控制油门都可以。我们将接收器连接到树莓派的GPIO接口上,用哪一个接口都可以。接收机上通常有4个通道的信号输出接口(你的接收机或许是6通道的,或者更多,但我们只使用其中的3个通道),每一个信号接口都有3根引脚,分别是5V、GROUND、SIGNAL,所有的5V都接在树莓派的5V引脚上;所有GROUND都接在GND引脚上。

        注意:遥控器在第一次使用时需要进行遥控器与接收机的对码,如何给遥控器对码请参见购买时的使用说明书,这里我们不再赘述。


        这里,我们用的接线引脚是15、16、1。这只是个例子,在实际接线时一定要注意引脚的编号,别弄错了。当接线完成时,你就可以写一个程序来读取接收机的3个通道数据。

        首先初始化引脚15为输入引脚(这与我们之前用的电调是一个引脚号,在实际接线时要把电调和接收机信号分开接到不用的GPIO引脚上)为输入模式:

wiringPiSetup();
pinMode(15, INPUT);

        二、使用循环计时方式读取遥控器信号(不推荐)

        再来看一下如何通过程序来读取树莓派的引脚,从而取得摇控器接收器的通道值:

void driver_ctl_LR()
{
        //高电平开始
        struct timeval start;
        //高电平结束
        struct timeval end;
        int s = 0;
        int f = 0;
        //循环接收信号
        while (1)
        {
                s = 0;
                f = 0;
                do
                {
                        //读取引脚的值
                        int lr = digitalRead(15);
                        //如果是高电平则计时开始
                        if (lr == 1 && s == 0)
                        {
                                gettimeofday(&start, NULL);
                                s = 1;
                        }
        
                        //如果已经开始计时,并且读到低电平,说明信号读取结束
                        if (s == 1 && lr == 0)
                        {
                                //高电平结束(低电平)
                                gettimeofday(&end, NULL);
                                //计算高电平持续时间
                                long timer = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
                                //得到PWM信号做出相应动作
                                engine_lr_pwm(timer);

                                break;
                        }

                        //超时检测
                        if (s == 0 && lr == 0)
                        {
                                if (f == 0)
                                {
                                        gettimeofday(&start, NULL);
                                        f = 1;
                                }
                                //如果持续低电平
                                if (f == 1)
                                {
                                        //如果低电平持续时间超过1秒,跳出
                                        gettimeofday(&end, NULL);
                                        long timer = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
                                        if (timer > 1000000)
                                        {
                                                break;
                                        }
                                }
                        }
                }
                while (1);
        }
}

        这样就可以得到引脚15的PWM信号了,顺便说一下:摇控器接收机的信号通常也是PWM信号,通常是在1.0ms到2.0ms之间。

        这样的程序虽然可以得到遥控器的读数,但有一个非常大的问题就是占用CPU的时间非常占用率非常高。

 

        三、使用中断方式读取遥控器信号(推荐)

        为了让我们的程序把CPU的占用率降低下来我们可以使用GPIO中断的方式来读取乳制品遥控器的读数,中断方式是计算机处理外部设备时常用的一种方式,,在使用Wringpi处理中断时我们需要初始化一个GPIO引脚为输入,并为其指定中断处理函数,也就是说当中断发生之后weiringpi程序会自动回调我们的处理函数,例如:

 

//设置摇控器3个通道到GPIO为输入引脚
pinMode(15, INPUT);
pinMode(16, INPUT);
pinMode(1, INPUT);

//注册摇控器3个通道的引脚变化中断
wiringPiISR(15, INT_EDGE_BOTH, &controller_ctl_pwm_fb);
wiringPiISR(16, INT_EDGE_BOTH, &controller_ctl_pwm_fb);
wiringPiISR(1, INT_EDGE_BOTH, &controller_ctl_pwm_fb);

void controller_ctl_pwm_fb()
{
	//处理功能
}
void controller_ctl_pwm_lr()
{
	//处理功能
}
void controller_ctl_pwm_pw()
{
	//处理功能
}

 

        这样,我们就注册了3个回调函数函数当GPIO引脚的电平发生变化时WiringPi就会自己调用这3个函数,我们可以在处理函数中这样写:

void controller_ctl_pwm_fb()
{
	//读取电平信号
	s32 value = digitalRead(15);
	//如果是高电平
	if (value)
	{
		//计时开始
		gettimeofday(&ctl_pwm->timer_start, NULL);
		return;
	}

	//如果是低电平,计时结束
	gettimeofday(&ctl_pwm->timer_end, NULL);
	//计算高电平时长,即pwm占空比
	timer = (ctl_pwm->timer_end.tv_sec - ctl_pwm->timer_start.tv_sec) * 1000000 
            + (ctl_pwm->timer_end.tv_usec - ctl_pwm->timer_start.tv_usec);
}

 

        当然我们在程序中写的GPIO引脚编号只是为了便于调试而设置的15、16、1。了解了遥控器信号和读入的原理之后我们就可以任意指定其编号了。

        得到了一个通道的信号,那么再取其它通道的信号也就没有什么难度了,我们可以读取摇控器上4个通道的任意3个,并把它们做为控制四轴的“前/后”、“左/右”、“上/下”。所以我们说你使用摇控器时,选择日本手还是美国手其实并不太重要,你可以把任意一个通道变为你想要的功能。

    返回首页    返回顶部
#1楼  njxxcs  于 2016年12月29日17:44:40 发表
 
请问作者,最新版的程序使用的是BCM引脚编码还是wiringpi的编码?
#2楼  李德强  于 2016年12月29日23:01:33 发表
 
感谢您的支持!程序中用到的GPIO编号均为wiringpi编号。
#3楼  匿名  于 2017年01月20日21:57:51 发表
 
支持问渠网
#4楼  匿名  于 2017年01月20日21:58:18 发表
 
支持问渠网
#5楼  李德强  于 2017年04月16日14:50:52 发表
 
我使用的这一款接收机的接线引脚为

12 -> 2 ;

14 -> 4 ;

13 -> 3 ;

4 -> 6 ;

左侧是树莓派的wiringPI编号,右侧是收机的通道编号
  看不清?点击刷新

 

  Copyright © 2015-2018 问渠网 辽ICP备15013245号