基于 Android 的视频控制小车

由声网 Agora 举办的首届AI in RTC 大赛,已在10 月 24 日圆满落幕。其中,参与创意编程赛道的 100 多支参赛队伍在 3 个多月里挥洒创意与热情,带来了许多用心的项目。我们邀请了获奖的参赛队伍们,逐一分享了他们的开发实践。

buggy 团队基于 Android 手机、开发板、传感组件等,开发了一个可通过手机远程控制,支持视频的小车。

以下内容由buggy 团队撰写:

在消费电子设备的迅猛发展趋势下,智能手机的价格变低、配置却变高,越来越多的人选择更换配置更高的智能手机。旧手机如果没有被回收利用,其中的重金属和塑料将会对环境造成不可逆转的严重污染,令人惋惜的是绝大部分的旧智能手机还能正常使用。目前,对旧手机的主流处理办法是回收提炼贵金属,但提炼过程中还是会产生有毒有害气体。

智能手机的摄像头已经满足一般的图像采集要求。将旧智能手机摄像头利用起来,开发视频监控应用,成为旧手机重新利用的一大趋势[1],可以节省大量的视频采集设备成本,还能减少环境污染和资源浪费。

印度Mindhelix初创团队开发的智能安防产品Rico将旧智能手机利用起来,做出了一种有创意的安防产品。Rico主要由旧智能手机、智能插座,Rico内置的各种环境传感器及手机应用程序等软硬件组成。将旧智能手机装上应用程序,插入Rico中,原本要报废的智能手机就承担起视频摄像、人脸识别、语音控制、麦克风通话、行程提醒和音乐播放等功能。Rico内置的各种环境传感器可以监测一氧化碳、煤气、烟雾浓度、温度、湿度、灯光强度和运动;智能插座可以连接到家里的各种家用电器和电灯,控制其开启和闭合;所有监测到的数据通过API接口上传至云端,在手机应用程序上可以查看家庭环境的各项指标。例如温度、湿度等。如果出门忘记关灯,可以通过手机远程控制电灯关闭[2]。

在北美比较受欢迎的阿福管家(Alfred),是由台北初创团队研发的一款把旧手机变为监控摄影机的APP,提供动态侦测、推播通知、即时录影、夜视功能。用户只需要在两个智能手机上安装APP,一个设定为相机端,另一个为监控端,两端登入同一个Google帐号,便可以通过WIFI或3G/4G实现远程监控[3][4]。

研究设想

当今在安防监控领域,大多数民用监控设备有几大弊端:

  1. 位置固定:大多数设备位置固定,不便移动,即使有一些可以摄像头可以转动,但是仍然无法实现对大部分区域的监控,比如一些存在死角的位置就不会被监控(床底,墙角等等)。
  2. 有线传输,电源线:大多数是有线传输,即使有一些是无线传输,但是仍要被束缚在电源线上。
  3. 价格昂贵:当今一套完整的监控设备成本较高。

思路规划与作品设计

思路规划

此设计要求实现一个手机可以远程通过WIFI查看小车上的手机摄像头拍摄的画面并控制小车移动。利用淘汰的智能手机的摄像头,实时采集视频图像信号并通过无线WIFI网络将视频信号实时传输到手机端观看,再通过小车上的手机的红外遥控功能对小车进行移动方向、速度的控制。使用C语言开发单片机程序,用Java语言开发安卓程序。

此小节围绕安卓端视频传输方案的选择、单片机的选择、车身的选择、马达驱动的选择和遥控控制模块的选择展开讨论。

安卓端视频传输方案的选择

查阅相关文献和资料后对Android的实时图像传输的图像数据处理方式进行了汇总,总结出下表中的五套Android实时图像网络传输方案[5]。

在因特网环境下,方案1不可取。方案2中MediaRecorder有很强的硬件依赖性,因此不同的手机表现是不一样的,有的手机数据传输的时候会出现阻塞现象,实时性就降低了。方案3和方案4实时性低。方案5平均流量消耗高,也不可取。

这里采用另一种方案,使用声网Agora的视频通话 SDK进行二次开发。既保证了实时性,又降低了开发难度。

单片机的选择:单片机用于接收红外信号并控制马达驱动,根据在网上教程比较多的单片机是STC89CXX系列,STC89C52RC单片机是STC89C52的升级版,不断发展的半导体工艺也让该单片机的功耗不断降低。不仅仅是做到了能耗上的升级,也进一步加强了单片机的处理性能。所以选择STC89C52RC型号。

车身的选择:第一种方案,淘宝上购买用于此设计的车身。小车底盘和顶面采用3mm厚亚克力板经激光切割整体成形,并预留了多组安装孔,扩展能力强。利用小车的圆形底盘特性,在底面左右两边直流马达和橡胶防滑车轮,前后两个万向轮起平衡小车作用。直流马达更是容易控制及调速,而且这种玩具车架一般都价格便宜;第二种方案,自己做一个车身。采用铝合金板制作,需要切割板钻孔。此过程非常耗时,应该将时间用在程序开发上。所以采用第一种方案从淘宝上购买车身。

马达驱动的选择:方案1,通过继电器控制马达的运动状态。好处是结构简单,但工作原理为机械结构,所以坏处是反应慢,而且占用的空间大;方案2,采用TI公司的马达专业驱动芯片L293D。电压最大36V,峰值电流最大1.2A,0.6A连续额定电流。采用TTL电平信号控制。具有两个使能控制器,可做PWM信号输入端,用来调整马达速度[5]。综上选择方案2。

遥控控制模块的选择:方案1,使用红外遥控。虽然红外的遥控的控制距离只有10m左右,无法绕过障碍物进行遥控。但发射红外遥控信号的手机就架在小车上,可以将手机的红外发射器和红外接收器放在一块固定住。虽然并不是所有的安卓手机都有红外发射器,但都有3.5mm的耳机接口,红外信号的38kHz频率在音频范围内,可以用耳机接口外接的红外发光二极管发射红外遥控信号[6];方案2,可以用蓝牙来完成对小车的控制,小车上需要配备蓝牙模块与手机进行配对通信。但并不是所有的手机都支持蓝牙,早期的一些安卓智能手机就不支持蓝牙。相比蓝牙模块,红外模块成本更低。所以采用方案1。

设计构思

本设计是以安卓手机为控制核心,在手机控制端实时查看小车上的手机摄像头采集到的图像,并发送控制命令发给小车上的手机,再通过手机被控制端红外发送动作指令。VS1838B为红外接收模块,接收手机端的红外遥控信号,再交给STC89C52RC单片机判断红外遥控的码值,对应控制L293D马达驱动,从而实现小车的前后左右移动。电源采用2节18650锂电池串联供电。

3.4系统框图
本系统的系统框图如图所示。

项目实现

小车硬件电路设计

整个小车的硬件设计可以分为四个模块:电源电路、单片机最小系统、马达驱动模块、红外接收模块。电源电路为单片机最小系统、红外接收模块、马达驱动和两个车轮马达供电。

单片机最小系统

单片机的最小系统就是让单片机能正常工作并发挥其功能时所必须的组成部分,也可理解为是用最少的元件组成的单片机可以工作的系统[7]。单片机最小系统的系统框图和电路原理图如图所示。

image

图:单片机最小系统框图

图:单片机最小系统原理图

STC89C52RC单片机可谓是国产单片机发展历程上的一块里程碑,初步做到了国内量产。而52单片机则是51的升级版,不断发展的半导体工艺也让该单片机的功耗不断降低。不仅仅是做到了能耗上的升级,也进一步加强了单片机的处理性能。在保持原有的8位处理器不变的大方针下,采用了CMOS的生产工艺STC89S52RC单片机片内集成512字节RAM、8K字节ROM。在烧写次数方面达到了1000次左右的优良性能,低功耗模式情况下时钟系统虽然会停止工作,但是内部的寄存器还是能够进行正常的处理。为了适应不同的使用场合,这款单片机提供了多种封装,本次设计根据最小系统有时需要更换单片机的具体情况,使用双列直插DIP-40的封装,配合缩紧底座。

马达驱动模块

L293D是TI公司的产品,比较常见的是16脚PDIP封装。L293D通过TTL电平信号控制,由OUTPUT1,OUTPUT2和OUTPUT3,OUTPUT4驱动2个马达。INPUT1、INPUT2、INPUT3、INPUT4脚连接STC89C52RC的P0. 0、P0. 1、P0. 2、P0. 3口,控制马达的运动状态。ENABLE1,ENABLE2为控制使能端,对应与单片机的P0. 4、P0. 5口相连,控制马达的停转和PWM调速[8]。P0. 4、P0. 5口通过输出不同占空比的PWM波形来改变马达的快慢。占空比是指高电平持续时间在一个周期时间内的百分比。单片机输出PWM信号可采用软件延时或定时器两种方法,在此用的是软件延时的方法。当高电平延时时间到时,电平取反变成低电平,然后再延时;当低电平延时时间到时,电平取反变高电平,一直这样反复就能得到PWM波形[9]。VSS可接4.5~7V电压,给芯片的逻辑电路提供电压。VS电压范围为4.5~36 V,给输出端提供电压。L293D的真值逻辑和功能的对应如表4-1所示。
表L293D真值逻辑和功能对应表

红外遥控模块

红外遥控模块主要由遥控发射器、红外接收头、接口电路组成。红外遥控器用来产生遥控编码脉冲,驱动红外发射管输出红外遥控信号,这里使用的使手机自带的红外发射功能。遥控接收头完成对遥控信号的放大、检波、整形、解调出遥控编码脉冲,这里使用一体化红外接收头来完成这一系列操作。遥控编码脉冲是一组串行二进制码,此串行码输入到单片机,由其内部CPU完成对遥控指令解码,并执行相应的遥控功能[9]。

红外遥控的实现原理

本次红外遥控采用的是NEC协议,调制方式为PPM脉冲位置调制,载波38kHz。位0和位1所不同之处就是在高电平脉冲后的低电平脉宽不一样,逻辑1为2.25ms,脉冲时间560us;逻辑0为1.125ms,脉冲时间560us。其波形如图所示。

image image

图:遥控码的0和1

下图是NEC的协议格式。首先是引导码,9ms的高电平脉冲和4.5ms的低电平,接下来是8位的地址码和8位的地址反码,用于校验地址码, 然后是8位的命令码和8位的命令反码,用于校验码[10]。

图:NEC协议格式

红外接收模块

本次采用的是VS1838B 一体化红外接收头有三个引脚,其外观和引脚排列如图4-6所示。OUT端即解调信号的输出端,连接单片机的P3. 2口。

小车软件设计

这次设计可以用C语言编程序,也可以用汇编语言编程序,现在的单片机内部容量已经比较大了,可以使用C语言编写程序,不必使用晦涩难懂的汇编语言[11]。所以本次设计中系统程序用C语言编写程序,用软件Keil C51编译。

主程序设计

在本设计中,单片机主要是在主程序的控制下,定时对红外一体化接收头VS1838B接收的红外信号进行识别分析,读出的数据如果为0x12、0x18、0x14、0x16则分别对应控制小车的前进、后退、左转、右转。小车硬件系统软件设计的流程图如图4-7所示。

图:主程序流程图

主要代码如下。

void main(){
	IrInit();//初始化
	ENA=0;
	ENB=0;
	T=2048;
	speed=400;//数字越大速度越快  
	ENA=1;
	ENB=1;
	while(1){
		  detectorIR();//判断红外信号
		  motorRun();//控制电机状态
		  if(speed!=T){
		   ENA=0;
		   ENB=0;
		   delay(T-speed);
		   ENA=1;
		   ENB=1;
		   delay(speed);
		   }
	}		
}

红外遥控接收程序设计

红外遥控接收程序的重心在于解码的方式,解码方法如下:

  • 步骤1 设外部中断0(或者1)为下降沿中断,定义一个变量Time用来计时,初始值为0。
  • 步骤2 第一次进入遥控中断后,开始计时。从第二次进入遥控中断起,先停止计时。并将计时值保存后,再重新计时。如果计时值等于前导码的时间,前导码标志为真。准备接收下面的一帧遥控数据,如果计时值不等于前导码的时间,但前面已接收到前导码,则判断是遥控数据的0还是1。
  • 步骤3 继续接收地址码、地址反码、数据码、数据反码。
  • 步骤4 当接收到32位数据时,说明一帧数据接收完毕。此时可停止计时,并判断本次接收是否有效,如果两次地址码相同且等于系统的地址,数据码与数据反码之和等于OFFH,则接收的本帧数据有效。否则丢弃本次接收到的数据。
  • 步骤5 接收完毕,保存本次接收数据,准备下一次遥控接收。

图:红外解码流程图

主要代码如下。

void ReadIr() interrupt 0
	{
		u8 j,k;
		u16 err;
		Time=0;					 
		delay(700);	//7ms
		if(IRIN==0)		//确认是否真的接收到正确的信号
		{	 
			
			err=1000;				//1000*10us=10ms,超过说明接收到错误的信号
			/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
			侯,程序死在这里*/	
			while((IRIN==0)&&(err>0))	//等待前面9ms的低电平过去  		
			{			
				delay(1);
				err--;
			} 
			if(IRIN==1)			//如果正确等到9ms低电平
			{
				err=500;
				while((IRIN==1)&&(err>0))		 //等待4.5ms的起始高电平过去
				{
					delay(1);
					err--;
				}
				for(k=0;k<4;k++)		//共有4组数据
				{				
					for(j=0;j<8;j++)	//接收一组数据
					{

						err=60;		
						while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
						{
							delay(1);
							err--;
						}
						err=500;
						while((IRIN==1)&&(err>0))	 //计算高电平的时间长度。
						{
							delay(10);	 //0.1ms
							Time++;
							err--;
							if(Time>30)
							{
								return;
							}
						}
						IrValue[k]>>=1;	 //k表示第几组数据
						if(Time>=8)			//如果高电平出现大于565us,那么是1
						{
							IrValue[k]|=0x80;
						}
						Time=0;		//用完时间要重新赋值							
					}
				}
			}
			if(IrValue[2]!=~IrValue[3])
			{
				return;
			}
		}			
	}

安卓程序设计

本设计的安卓程序能够使用手机摄像头实时地将手机拍到的图像传送到手机端或电脑端,同时接收手机端或电脑端发出的指令。根据指令小车上的手机再发送相应的红外遥控信号给小车,手机安卓程序是小车端和控制端二合一的,在初始界面进行选择,主要是实现接收和发送信令、实时音视频传输和红外信号传输等功能。

Android开发包及其工具的安装和配置
本次开发使用声网(Agora)的视频通话和信令的SDK进行二次开发。下面介绍在正式使用 Agora SDK for Android进行通话/直播和信令控制前,需要准备的开发环境,包含前提条件及SDK集成方法等内容[12]。
请确保满足以下开发环境要求:

  1. Android Studio 3.0或以上版本
  2. App要求 Android 4.1或以上设备
  3. Android SDK API Level ≥16

在编译和启动实例程序前,需要首先获取一个可用的App ID:

  1. 在agora.io创建一个开发者账号
  2. 前往后台页面,点击左部导航栏的“项目”→“项目列表”菜单
  3. 复制后台的App ID并备注,稍后启动应用时会用到它

集成Agora视频SDK:

  1. 在项目对应的模块的app/build.gradle文件的依赖属性中加入通过JCenter自动集成Agora视频SDK的地址,语句如下:
    implementation ‘io.agora.rtc:full-sdk:2.4.1’
  2. 在Agora.io官网下载agora-rtc-sdk.jar和agora-sig-sdk.jar,解压后将其中的libs/include 文件夹下的所有头文件复制到本项目的app/src/main/cpp/agora目录下。

完成以上步骤后,用Android Studio打开该项目,连上设备,就可以编译并运行程序了。

手机端程序的设计

因为Android4.4及以上才有ConsumerIrManager类用来操控红外设备,所以本程序是基于Android 5.1系统的OPPO A51手机开发和测试的。用Android Studio开发,在此开发环境下完成Android手机终端的相关应用开发非常的方便[13]。
手机控制端实时视频功能的程序流程图如图所示。

具体使用方法见声网官网文档中心的参考[12],这里就不进行详尽描述了。下面来对主要步骤进行简单介绍。

(1)初始化

进入频道之前,调用create创建一个实例。

import io.agora.rtc.Constants;
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;//初始化前先导入这4个包
...
private void initializeAgoraEngine() {
    try {
        mRtcEngine = RtcEngine.create(getBaseContext(),
getString(R.string.agora_app_id),
                              mRtcEventHandler);
    } catch (Exception e) {
        Log.e(LOG_TAG, Log.getStackTraceString(e));
        throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
    }
}

(2)加入频道

App在加入频道前,需要先设置频道模式,再加入频道。
创建实例后,调用setChannelProfile方法设置频道模式。

mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);

之后调用joinChannel方法加入频道。

 private void joinChannel() {
    mRtcEngine.joinChannel("token", "demoChannel1", "Extra Optional Data", 0); 
}

(3)离开频道

调用leaveChannel方法离开频道,结束或退出通话或直播。

 private void leaveChannel() {
    mRtcEngine.leaveChannel();
}

(4)信令的实现

信令的具体使用方法见声网官网文档中心的参考[14],这里就不进行详尽描述了。主要使用的函数如下:

// 初始化信令 SDK
m_agoraAPI = AgoraAPIOnlySignal.getInstance(context, appID);
// 登录 Agora 信令系统
m_agoraAPI.login2(appId, account, token, uid, deviceID, retry_time_in_s, retry_count)
/////////////频道测试///////////////
// 加入频道
m_agoraAPI.channelJoin(channelName)
// 发送频道消息
m_agoraAPI.messageChannelSend(channelName, msg, msgID)
// 设置对端接收到频道消息回调
m_agoraAPI.onMessageChannelReceive(channelID, account, uid, msg) {
      // code there
}
// 退出 Agora 信令系统
m_agoraAPI.logout()

小车上的手机实时视频功能的程序流程图如图所示。

图:视频传输流程图

手机端红外线发射功能的程序流程图如图所示。

图:手机端红外发射流程图

因为Android4.4及以上才有ConsumerIrManager类用来操控红外设备,所以以下程序是基于Android 5.1系统的OPPO A51手机开发和测试的。

首先从系统服务中获取到ConsumerIrManager服务。

IR=(ConsumerIrManager)getSystemService(CONSUMER_IR_SERVICE);

然后将要发送的红外码存入数组中。

//0x73
    int[] pattern2 = { 9000, 4500, 
      560, 560, 560, 560, 560, 560, 560, 560, 560,560, 560, 560, 560, 560, 560, 560, 
      560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 
560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 
560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 1690, 560, 1690,560, 1690, 
            			560, 42020, 9000, 2250, 560, 98190 };

数组中存放的是数值代表的是一种交替的载波序列模式,通过毫秒测量。这6行数据依次表示引导码,地址码,地址码,数据码,数据反码,连续码,具体原理详见4.1.3节红外遥控原理。

第三行数据码反置,比如0x12=0001 0010反置为 0100 1000,只有反置了之后才能接收正常。最后通过如下方法最终发送红外信号。

mCIR.transmit(hz, pattern2);//后退 

transmit(int carrierFrequency, int[] pattern) :此方法控制手机产生 carrierFrequency为频率的,以pattern为红外开关的时间数组,发送红外信号。(例如:transmit(38000,{100,200,300,400}) 将会产生一个频率为38KHz的红外信号,信号的电平高低为 100us高电平,200us低电平,300us高电平,400us低电平。注意pattern的数据个数要为偶数个,不然报错。)[15]。

参考文献:

[1]赵允乐.基于Android手机摄像头的视频监控平台设计与实现[J].电脑编程技巧与维护,2016(17):36-37.
[2]虾壳大米.Mindhelix把废手机变成智能家居的一部分[OL].http://www.shejipi.com/31209.html,2019-01-01.
[3]Chony Lu.用Google推荐的App,把闲置手机变成摄像监控吧-Alfred阿福管家#iOS#Android[OL].https://chuansongme.com/n/1454011422557,2019-01-01.
[4]王烨.基于Android系统的智能导航小车设计[D].天津:天津大学,2014.
[5]android实时视频网络传输方案总结(一共有五套)[OL].https://blog.csdn.net/findsafety/article/details/72637795,2019-01-01.
[6]安卓手把手教你学习并实现 安卓耳机口音频转红外发射[OL].https://blog.csdn.net/u012534831/article/details/78776999,2019-01-01.
[7]聂茹.基于Android手机蓝牙控制的智能小车设计与实现[J].微型电脑应用,2015,31(09):68-69+74+6.
[8]朱涛.基于STC89C52单片机的智能循迹小车设计[J].电脑知识与技术,2011,7(31):7751-7753+7758.
[9]赵海兰.基于单片机的红外遥控智能小车的设计[J].无线互联科技,2011(03):36-38.
[10]刘西江.基于单片机的AGV小车红外遥控的可实现性[A].河南省汽车工程学会.第十三届河南省汽车工程科技学术研讨会论文集[C].河南省汽车工程学会:河南省汽车工程学会,2016:4.
[11]徐爱钧.单片机C语言编程与Proteus仿真技术[M].北京:电子工业出版社,2016.
[12]集成客户端[OL].https://docs.agora.io/cn/Video/android_video?platform=Android,2019-07-01.
[13]巅峰卓越.Android从入门到精通[M].北京:人民邮电出版社,2016.
[14]发送频道消息[OL].https://docs.agora.io/cn/Signaling/signal_android-1?platform=Android#发送频道消息,2019-07-01.
[15]Android编程红外编程——红外码详析[OL].https://blog.csdn.net/sir_zeng/article/details/80591065,2019-07-01.
[16]宋继超.安防机器人控制系统设计与实现[D].电子科技大学,2018.
[17]Android实践:做一个可视频交互的智能小车[OL].https://blog.csdn.net/weixin_33786077/article/details/87947763,2019-05-22.

1赞