这个工程是毕业论文的一部分,主要工作是改造一辆能够被安卓手机控制的小车。通过对安卓手机编程,能够在蓝牙的通信范围内遥控小车。
小时候家里玩具少,看到遥控车总是很羡慕。正好毕业设计题目自选,就想着做一个能被手机控制的安卓小车。因为实验室方向是图像处理和模式识别相关专业,有意将这个安卓小车作为一个模式识别的实验平台。安卓手机可以安装在小车上,根据手机采集的图像来进一步的实验。任何有趣的想法可以移植到手机上控制小车自动运行。
总的来说,这个工程可以分为两部分:小车端和手机端。下面,将分别对这两个模块进行介绍。
小车是在淘宝上买的模型,随手一搜大脚车到处都是。这个模型车自带2.4G的遥控器,遥控范围大概在100m左右。采用的是7.2V直流电机,虽然电压不高,但是性能绝对强劲,下面是小车刚买回来的样子,左边一幅图车顶加了个摄像头,右边的图拆了外壳,巨大的直流电机加散热罩霸气外泄。
拆开仔细研究之后发现小车前进后退的动力是直流电机,通过一块L298芯片驱动(图中的电调)。而左右的转向是通过一个舵机控制前轮来实现。遥控器的接收机接收到信号之后,发送PWM波到电调和舵机,通过调节PWM的占空比来控制前进和转向。我猜测遥控器接收机的三个通道输出的是同样的标准舵机控制信号,这一想法在示波器上得到了印证。
针对这个特点,改造的思路是在车上加一块MCU,通过MCU来生成遥控器输出的PWM波,直接接入到电调和舵机,从而实现小车的控制。这样的改造方案无需额外的直流电机控制器,并且,可以方便地在MCU信号和遥控器接收机信号之间进行切换。
根据这一想法,在车上装了一块Arduino Nano MCU,并且MCU连接了一块蓝牙模块,通过串口与蓝牙通信。为了对小车速度进行测量,我还给小车加装了一个光点码盘。整个加装的电路图如下所示:
为了方便控制信号的切换,输入电源由一个双向开关控制,当拨动到左边时,遥控器接收机通电,可以通过遥控器控制小车。当拨向右边时,MCU通电,通过MCU来控制小车。最后装上MCU、开关之后的定妆照:
在这一步中,需要让MCU输出合格的PWM波,首先来看一下舵机的控制。
舵机,也称为伺服电机,是一个糅合了多项技术的科技结晶体,它由直流电机、减速齿轮组、传感器和控制电路组成,是一套闭环反馈自动控制装置。舵机的角度检测器是它的输入传感器,舵机转动的位置变化时位置检测器的电阻值就会跟着变化。通过控制电路读取该电阻值的大小,就能根据阻值适当调整电机的速度和方向,使电机向指定角度旋转。常用的舵机有一个三线的接口,分别是地线,5V信号线,和电源线。舵机的控制信号是PWM波,PWM波与舵机的转动关系如下图所示:
在标准的舵机信号中,脉冲的高电平持续1到2毫秒(ms),也就是1000到2000微秒(µs) 。在1000µs时,舵机左满舵。在2000µs时,右满舵。当然也可以通过调整脉宽来实现更大或者更小范围内的运动。
对于小车的前进与后退而言,当输入PWM波的高电平持续时间为小于1500微秒时,舵机向左旋转,小车向左转弯。当输入PWM波的高电平持续时间大于1500微秒时,舵机向右旋转,小车向右转弯。在这一过程中,小车的转弯角度与舵机旋转角度成正比。当输出PWM波的高电平持续时间为1500微秒时,舵机处在正中位置,小车直走。
使用Arduino MCU的优势在于,它提供了从硬件到开发环境的整套解决方案,并且包含了很多MCU使用的库,其中就舵机控制库Servo Lib。这让舵机的控制变得非常简单,需要做的只有四步:
#include <Servo.h> //(1)引用库文件
Servo driveMotor; //(2)声明一个伺服电机对象
//设置程序
void setup()
{
...
angleServo.attach(9);//(3)将该伺服电机绑定到Pin9上,Pin9能够输出PWM波。
...
}
//主程序
void loop() {
...
driveMotor.writeMicroseconds(1500);//(4)输出高电平持续时间为1500us的PWM波
...
}
剩下的串口通信和光电编码器计数也非常简单,具体可以参考源代码。
在调试的过程中发现,如果不对速度进行闭环控制,给定一个速度,小车速度表现非常不稳定,尤其是当遇到障碍物时,要么过不去,要么速度过快。因此,需要对小车进行闭环反馈控制。
闭环控制系统对实际输出的量进行测量,并将实际输出与预期输出进行比较,将获得的偏差作为控制的依据,并用于实际的控制过程,以使偏差不断地减小。小车的速度闭环反馈控制回路的框图如下图所示:
其中的 PID 控制器可用如下方程来表示:$$u(t) = {K_p}e(t) + {K_I}\int {e(t)dt + {K_D}{{de(t)} \over {dt}}} $$
$u(t)$为控制器输出的控制量,$e(t)$为偏差,是由预期的输出响应与实际输出响应的测量值的差,上式右边是比例项、积分项与微分项之和,${K_p},{K_I},{K_D}$为相应项的系数,也称为控制增益。对上式进行离散化,并采用增量式PID控制。在最终的参数整定时,包含了积分项和微分项。小车这个系统最终整定的结果是:${K_p}$=195,${K_I}$=5,${K_D}$=1.25,阶跃响应曲线为:
从图中可以看出,小车的上升时间为0.8s,超调量为0,响应速度很快,并且速度稳定。小车将接收到的速度作为PID的输入,控制小车按照客户端设定的速度前进。
在完成小车端的改装之后,需要编写一个安卓客户端,要能够与小车上的蓝牙模块进行通信,同时要将手在屏幕上的触摸位置变为控制命令发到小车端。
考虑到可能需要单手操作和双手操作,软件包含竖放和横放两个界面:
单手界面只有一个控制板,包含了一个实心圆和外层的空心圆。这个控制板承担了方向和速度的控制功能。无论手在实心圆的哪个方向,到实心圆距离代表速度。当手落在实心圆里面时,小车静止;当手落在空心圆外面时,小车达到最大速度。当手落在圆心左边时,小车向左转,当手落在右边时,小车向右转。偏离圆心垂线越远,转向越大。
双手界面则将方向控制和速度控制分开来,左边控制方向,右边控制速度。功能解释与单手界面一致。
界面右上角有一个蓝牙标志,点击该标志将会进行设备搜索,并列出可选蓝牙设备,点击相应的设备就能进行连接了。
安卓客户端与蓝牙通信的程序是从Android SDK中的Sample改写而来,因此,在这里不做过多的介绍。在这里,蓝牙程序只有发送,而不会接收小车的消息,相对比较简单。
当连接上小车的蓝牙设备后,当手进入控制范围时,手机会新建一个线程,计算速度和方向,并每隔50毫秒将这些命令发送到手机,剩下的事情就交给手机了。
速度的计算用公式表示如下:$$speed = \sqrt {{{(x - {x_0})}^2} + {{(y - {y_0})}^2}} .$$
方向的计算公式如下:$$angle = atan 2({{y - {y_0}} \over {x - {x_0}}})$$
其中,$(x_0 ,y_0)$是实心圆的坐标,$(x,y)$是手指所在的位置的坐标。
源代码请访问:https://github.com/wenhuix/BluetoothCar
[1] Arduino官方网站,http://arduino.cc/
[2] 电路图使用Fritzing软件绘制:http://fritzing.org/home/
[3] http://developer.android.com/index.html
Last update: 2014-11-22