当前位置:   article > 正文

Arduino单片机(五).基于OpenWrt模块的无线视频遥控小车设计_wifi 视频小车

wifi 视频小车

1、功能介绍

本项目所设计的机器人需要实现的功能为:操作员在操作终端(手机或PC端)通过Wi-Fi连接到小车上Wi-Fi模块所在的网络中,向其发出相关操作指令,在Wi-Fi模块接收相关的数据指令并通过UNO R3单片机对这些数据进行解码,最后按照不同的指令信息利用单片机控制相应的外围电路从而实现遥控控制。与此同时,安装在机器人上的摄像头可以通过Wi-Fi网络将视频信息传递到相应操作终端,只要在同一个Wi-Fi网络下便可以在多个设备上直观地查看。实现了终端对底层电路的控制以及底层信息的回传,以便于操作员实时了解机器人周围的环境,并根据环境情况发出指令进而控制机器人执行特定的任务。

2、材料清单及硬件电路设计

硬件部分由车体部分,控制部分和无线部分等构成。车体部分由底板和4个直流减速电机组成,电机两两并联,相当于同时驱动一侧两个电机。车轮采用4个橡胶轮胎,体积小,质量轻,抓地性好。控制部分采用Arduino控制芯片,其上连接扩展板用于驱动四个电机运作。无线部分用OpenWrt路由器和高清摄像头组成。OpenWrt 是一个基于 Linux 的开源路由固件, 提供了一个完全可写的文件系统及软件包管理,对支持 OpenWrt 的路由器刷机后,其相当于一个Linux小系统。路 由 器 选 择OpenWrt 作为操作系统, 将 USB 摄像头采集的现场图片发给远端的 PC 控制终端,PC端显示相应的图像信息,并可接收上位机软件发送的控制信息后通过串口发送至单片机系统,并将上位机发出的命令通过串口转发给单片机控制系统,实现双向通信。硬件部分材料清单如下表中所示。

部件型号数量
底板亚克力透明车底盘板1
直流减速电机直条双轴减速马达4
车轮橡胶车轮4
摄像头浪景高清摄像头1
路由器64M大内存WiFi模块1
单片机Arduino UNO R31
扩展板电机驱动(L298N)1

使用Arduino UNO R3开发板的4、5号端口的输出功能控制小车的左侧两个电机;6、7号端口的输出功能控制小车的右侧电机。开发板的接收数据引脚(RX)连接WiFi无线传输模块的发送数据引脚(TX),同时它的发送数据引脚(TX)连接WiFi模块的接收数据引脚(RX)。WiFi模块用USB数据线连接高清摄像头。WiFi天线用于接收和发送与手机端软件相互通信。电路设计图如下图中所示,需要注意的是单片机端口和电机之间需要通过电机驱动模块来连接,在这里我们使用的是L298N驱动模块可驱动直流电机。
在这里插入图片描述

3、软件系统设计

3.1、终端软件部分

能够运行在Android手机上的APP,以及可运行在Windows系统的PC端上位机软件。通过手机端软件控制小车运动以及实时接收采集到的视频信息。以Android端软件为例,启动APP后,右下角的四个按钮可以控制小车前后左右运行,主界面用于查看小车采集到的图像视频信息;通过设置按钮可以设置小车IP地址,控制端口号,视频端口号等信息。

3.2、通信协议部分

上位机采用数据包格式传送指令,也可以采用单字符的形式发送,由于单字符通信方式干扰较大,因此采用数据包格式传送指令,包头用0XFF,包尾用0XFF,无校验位。上位机利用无线网卡通过Socket发送数据包到路由器,路由器通过解包机制把数据包解开,通过串口发送到单片机进而控制电路模块执行相关的操作。

3.3、电控软件部分

对于Arduino端的电控程序部分是本项目中最为核心的部分,其流程框图如下所示。整体的程序可分为解码和编码、运动控制以及串口数据收发三个模块,其中串口数据收发模块用于接收WiFi模块发送到单片机上的数据,以及向WiFi模块发送数据(数据由它转发到其它的终端设备);解码部分用于对单片机接受到的数据表进行解析转换成易于识别的字符形式,编码部分将单片机需要发送到终端设备的信息打包成与通信协议相应的格式;运动控制模块是描述小车的行为模式有前进、后退、左转、右转以及停止五种状态,通过使用单片机IO端口高低电平的输出配合电机的正反转便可以实现这些功能。
在这里插入图片描述

4、核心代码

4.1、主循环

void loop()
{
  
  getSerialLine();
  if (commandAvailable) {
    processCommand(strReceived);
    strReceived = "";
    commandAvailable = false;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.2、读取串口数据

void getSerialLine()
{
  //使用\r字符作为两条命令间隔符,拼接收到的字符
  while (serialIn != '\r')
  {
    if (!(Serial.available() > 0))//缓冲器无数据装入
    {
      return;
    }
    serialIn = Serial.read();//读取串口
    if (serialIn != '\r') {
      if (serialIn != '\n'){
        char a = char(serialIn);
        strReceived += a;
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

4.3、指令处理

void processCommand(String input)
{
	String command = getValue(input, ' ', 0);
	int val;
	if (command == "MD_Qian")
	{
		qian();
	}
	else if (command == "MD_Hou")
	{
		hou();
	}
	else if (command == "MD_Zuo")
	{
		zuo();
	}
	else if (command == "MD_You")
	{
		you();
	}
	else if (command == "MD_Ting")
	{
		ting();
	}
	else if (command == "MD_SD")
	{
		val = getValue(input, ' ', 1).toInt();
		leftspeed = val;
		val = getValue(input, ' ', 2).toInt();
		rightspeed = val;
	}
	//是否收到的是已经定义的命令,如果不是则不回送状态,免得浪费带
}
String getValue(String data, char separator, int index)//data(strReceived),' ',0
{
  int found = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = data.length() - 1;
  for (int i = 0; i <= maxIndex && found <= index; i++){
    if (data.charAt(i) == separator || i == maxIndex){//data.charAt(int val)返回val位置的char值
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";//data.substring(int a,int b),返回a到b位置的字符串
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

4.4、速度及运动状态控制

void qian(void)
{
  EN1Status = LOW;
  EN2Status = HIGH;
  EN3Status = LOW;
  EN4Status = HIGH;
  SetEN();
}
void hou(void)
{
  EN1Status = HIGH;
  EN2Status = LOW;
  EN3Status = HIGH;
  EN4Status = LOW;
  SetEN();
}
void you(void)
{
  EN1Status = LOW;
  EN2Status = HIGH;
  EN3Status = HIGH;
  EN4Status = LOW;
  SetEN();
}
void zuo(void)
{
  EN1Status = HIGH;
  EN2Status = LOW;
  EN3Status = LOW;
  EN4Status = HIGH;
  SetEN();
}
void ting(void)
{
  leftspeed = 0;
  rightspeed = 0;
  EN1Status = LOW;
  EN2Status = LOW;
  EN3Status = LOW;
  EN4Status = LOW;
  SetEN();
}
//设置两侧速度
void SetEN(){
  analogWrite(EA, leftspeed);
  analogWrite(EB, rightspeed);
  digitalWrite(EN1, EN1Status);
  digitalWrite(EN2, EN2Status);
  digitalWrite(EN3, EN3Status);
  digitalWrite(EN4, EN4Status);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

5、实物作品展示

不仅是这个基于OpenWrt模块的无线视频遥控的小车,图片中包含了本科时实验室里学长学姐、学弟学妹以及同学们的共同成果。现在想起来这一些东西都做的很简单,但在当时初学单片机时就点亮一颗LED灯都很兴奋。在学习嵌入式的这条路上,走走停停,似乎是凭借着爱好坚持了下来。最近也没有怎么做过单片机相关的项目了,所以想把这些东西写出来算是为我的大学生活做个总结吧!
在这里插入图片描述

6、写在最后

这是最后一节关于Arduino系列单片机应用的文章了,其实能够使用Arduino做的东西还有很多,也包含大量的有技术含量的项目。Open source带来了一次软件技术发展的高峰,在这一种开发方式中,任何人都能够得到源代码,在其基础上进行学习从而开发新的功能。在硬件方面上也是这样,开源硬件是与自由与开放原始码软件相同方式设计的计算机和电子硬件,Arduino正是开源硬件发展历程中的里程碑。类似的开源硬件还有Beagle、Raspberry PI(树莓派)等。本科时刚接触Arduino时,第一印象感觉它特别简单,不管是从软件程序的编写还是外部电路的扩展方面来讲。与便捷灵活、学习简单这些特点相对应的就是它的运行频率太低,在完成一些比较大一点的项目就会很吃力(相对于同类产品的性价比,如STM32)。当我利用Arduino平台做出了一些东西时,不得不说开源硬件的发展方便了硬件产品的很多开发步骤,也能够很快地实现自己的创意。关于Arduino单片机的学习资料如有需要可以私信我,最后希望开源硬件会发展的越来越好!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/1013085
推荐阅读
相关标签
  

闽ICP备14008679号