多功能控制小车

DIY小车这个项目已经很多了,对于前后左右等控制,司空见惯,这次尝试一下能监控的多功能控制小车,电脑,手机都可以!

多功能车基本功能参数和关键部件,视频传输这块和我们现在智能家具这块无线视频原理一样,下面会有介绍。

1.输入电源:2串或3串的锂电池(带充电器)

2.输出5v,3.3V等电压为负载供电

3.四个直流减速电机

4.WIFI数传模块

5.电机驱动模块

6.STM32F105主控板

7.UVC摄像头

8.小车底盘

最后实现电脑或手机通过wifi和软件控制小车动作并实时监控。

框图

基本框图:

基本编程软件

keil5

对于单片机编程这块,目前STM32占用非常多,涉及到库函数和寄存器编程。

这次采用库函数编程,采用传统的标准库,HAL库后续可以。

如上图所示,先把框架建立好,拿一个自己用的工程,把相应的函数添加进去就可以了。

舵机这块是两个,上下,左右各一个,180度旋转。

舵机的基本控制原理

控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:

   0.5ms--------------0度;

   1.0ms------------45度;

   1.5ms------------90度;

   2.0ms-----------135度;

   2.5ms-----------180度;

看看程序中是怎么控制的

用STM32硬件PWM和模拟PWM都可以

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;   //ÅäÖÃΪPWMģʽ1

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = Speed_Left-1;   //ÉèÖÃͨµÀ2µÄµçƽÌø±äÖµ£¬Êä³öÁíÍâÒ»¸öÕ¼¿Õ±ÈµÄPWM

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;   //µ±¶¨Ê±Æ÷¼ÆÊýֵСÓÚCCR1_ValʱΪ¸ßµçƽ

TIM_OC1Init(TIM5, &TIM_OCInitStructure);   //ʹÄÜͨµÀ1

TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);

我们改变这个值

Speed_Left-1就可以改变舵机角度。

这个是整个产品的核心wifi模块

wifi数传模块是基于MIPS 24K 高通CPU的一款WIFI1X1芯片AR9331,其SDK采用uboot作为引导。是基于MIPS 架构的,目前有x86、ARM和MIPS三种主流芯片架构,ARM集架构的主要特点:一是体积小、低功耗、低成本、高性能;二是大量使用寄存器且大多数数据操作都在寄存器中完成,命令执行速度更快;三是寻址方式灵活简单,执行效率高;四是命令长度固定,可通过多流水线方式提高处理效率。

wifi模块的工作原理

WiFi模块通过采集挂载在USB接口的MJPG格式的摄像头的数据,并编码封装成http协议的视频流,默认推送到8080端口。Android/IOS/PC设备,连接到WiFi模块的热点后,打开控制软件,会自动从8080端口获取MJPG视频流,并进行解码、显示。由此实现了WiFi智能小车的实时视频传输功能。

这个是实际的wifi图传模块

现在在重申一下这个模块的工作原理和使用方法

WiFi模块通过采集挂载在USB接口的MJPG格式的摄像头的数据,并编码封装成http协议的视频流,默认推送到8080端口。Android/IOS/PC设备,连接到WiFi模块的热(wifi-robots.com开头的SSID信号)后,打开控制软件,会自动从8080端口获取MJPG视频流,并进行解码、显示。由此实现了WiFi智能小车的实时视频传输功能。

我们简单恢复一下出厂设置就可以了,简单说一下,用USB转tll工具连接模块配置好波特率(57600)和串口号一定注意先后顺序。

1:点击打开串口,此时WIFI的状态是没有上电的。

2:给WIFI上电此时要注意串口开始打印(很关键)。

3:输入命令firstboot就可以了。

这个wifi模块怎么刷固件openwrt系统的。

首先通过USB口给设备供电,通过miniUSB口加上usb转网口网线连接电脑。

准备刷机工具TFTP服务端:tftp32  就是局域网内可以传文件。

超级终端:putty  Telnet、SSH、rlogin、纯TCP以及串行接口连接软件。

需要相应的固件具体教程http://www.wifi-robots.com/thread-108-1-1.html

最后我们看看USB摄像头这块,简单介绍一下无线监控中的摄像头。

1.摄像头选择

做本次实验的时候,推荐大家用 USB 免驱的摄像头,最好是支持 MJPEG 输出的摄像头类型。USB 免驱摄像头输出 YUV 格式和输出 MJPEG 格式,对无线监控的效果有什么影响呢?首先大家要知道,同样是一帧数据,YUV 格式会比 MJPEG 格式的大得多,因此我们在视频传输的时候,一般是传输 MJPEG 格式的数据。这样,就有这样一个问题,如果摄像头是输出 YUV 格式,那么就意味着我们需要通过软件将视频数据由 YUV 格式转换成 MJPEG格式,然后传输。如果摄像头输出的是 MJPEG 格式,那个将可以直接将得到的数据进行传输。因此,使用支持 MJPEG 压缩的摄像头,比一般的摄像头,做无线监控的效果,好很多。

2.配置 OpenWrt 支持 usb 摄像头

看看怎么配置

要支持摄像头,就必须配置上摄像头的驱动,因为是免驱的 USB 摄像头,因此我们必须配置上 UVC 驱动,具体如图所示。首先,我们选中内核模块进行配置:

选中 Video 支持配置:

按”y”选中 kmod-video-core:

在展开的选项中选中 uvc:

看看电机驱动模块:

基本原理如下

看看具体是怎么控制电机调速的,通过控制使能端使L298N处于工作和不工作,VSS-9引脚为芯片供电   VS-4引脚为电机供电   ENA-6引脚为通道1使能端,利用定时器的pwm输出作用于ENA,根据脉冲占空比不同就可以得到不同的输出电压,从而达到调速目的。比如在VS引脚加10V的电机供电电压,ENA端脉冲占空比为100%,那么OUT1和OUT2之间将输出10V电压,占空比为50%,那么输出为5V电压,占空比为10%,则为1V    我买的电机供电电压为5v到12v都可以,电压高的话也可以,长时间工作的话会对电机损坏。

看看电机是怎么正反装的

逻辑输入端,为IN1\IN2\IN3\IN4,其中IN1、IN2控制电机M1;IN3、IN4控制电 机M2。例如IN1输入高电平1,IN2输入低电平0,对应电机M1正转;IN1输入低电平0,IN2输入高电平1,对应电机M1反转,调速就是改变高电平的占空比。

这是整个系统的核心板STM32F105

正好国庆期间可以把程序写写,用一个stm32f103的模板,还是103的标准库,改一下测试再105上可以不?

主要就是串口这块,但是奇怪的是串口通讯不正常。

波特率9600是一致的,用串口助手发送,发送FE是没有任何反应的,发送其他,接受的也不一样,多年的编程,程序应该问题不大。

就怀疑时钟的问题,先软件仿真看看,调试状态找到RCC。

看看能看出来时钟对不

寄存器里面的值不太了解

可以通过一个时钟函数RCC_GetClocksFreq(&RCC_Clocks)加到主函数里,把RCC_Clocks变量加到窗口中,看看实际的时钟频率。

发现时钟不对,再网上查看资料说105和103的启动文件不一样。

宏定义这需要改成STM32F10X_CL。

由于105系列属于互联型单片机,默认晶振为25M,而我们实际为8M。

1.需要在这个stm32f10x.h文件里更改。

2.需要在这个system_stm32f10x.c文件里更改。

现在我们在仿真调试看看实际的时钟频率。

主频这个16进制值为0x044AA200,经过计算为72.000000。

这样就配置ok了。

为了让小车强劲有力,我们采用松下的18650电池,一个是2600MAH,两串两并的话就是8.4V ,总容量10400MAH。

这是两个电池的

加上快充充电器,网上买的,后续介绍。

我们现在准备组装小车。

这是小车底盘

组装锂电池

完毕。

剩下的小车组装完毕

下面开始程序调试

小车的电机直接有电池供电,L298N驱动。

舵机这块有电池降压5V供电

简单把程序这块介绍下,主要是串口通信。

最简单的串口数据处理机制是数据接收并原样回发的机制是:成功接收到一个数,触发进入中断,在中断函数中将数据读取出来,然后立即。这一种数据处理机制是“非缓冲中断方式”,虽然这种数据处理方式不消耗时间,但是这种数据处理方式严重的缺点是:数据无缓冲区,如果先前接收的的数据如果尚未发送完成(处理完成),然后串口又接收到新的数据,新接收的数据就会把尚未处理的数据覆盖,从而导致“数据丢包”。  

对于“数据丢包”,最简单的办法就是使用一个数组来接收数据:每接收一个数据,数组下标偏移。虽然这样的做法能起到一定的“缓冲效果”,但是数组的空间得不到很好的利用,已处理的数据仍然会占据原有的数据空间,直到该数组“满载”(数组的每一个元素都保存了有效的数据),将整个数组的数据处理完成后,重新清零数组,才能开启新一轮的数据接收。

解决这个问题采用FIFO的机制,环形缓冲区就是一个带“头指针”和“尾指针”的数组。“头指针”指向环形缓冲区中可读的数据,“尾指针”指向环形缓冲区中可写的缓冲空间。通过移动“头指针”和“尾指针”就可以实现缓冲区的数据读取和写入。

1.图形和代码分析

当然,环形缓冲区的“头指针”和“尾指针”可以用“头变量”和“尾变量”来代替,因为切换数组的元素空间,除了可以用“指针偏移法”之外,还可以用“素组下标偏移法”。当串口接收到新的数组,则将数组保存到环形缓冲区中,同时将“尾变量”加一,以保存下一个数据;应用程序在读取数据时,“头变量”加一,以读取下一个数据。

#define MAX_SIZE  12               //缓冲区大小

 

typedef struct 

{

  unsigned char head;        //缓冲区头部位置

  unsigned char tail;         //缓冲区尾部位置

  unsigned char ringBuf[MAX_SIZE]; //缓冲区数组

} ringBuffer_t;

 

ringBuffer_t buffer;                 //定义一个结构体

2.定义一个结构头体则表示新的消息队列已经创建完成。新建创建的队列,头指针head和尾指针tail都是指向数组的元素0。如下图所示,此时的消息队列是“空队列”。

当如果有11个数据abcdefghijk存入缓冲队列,则如下图所示:

当如果l加入队列,则缓冲队列处于满载状态,如下图所示:如果此时,接收到新的数据并需要保存,则tail需要归零,将接收到的数据存到数组的第一个元素空间,如果尚未读取缓冲数组的一个元素空间的数据,则此数据会被新接收的数据覆盖。同时head需要增加1,修改头节点偏移位置丢弃早期数据。

3.读取缓冲队列中的11个数据后,状态如下:

当消息队列中的所有数据都读取出来后,此时环形队列是空的,状态如下图所示。从图可以总结得知,如果tail和head相等,则表示缓冲队列是空的。

我们看看程序中是怎么做的。

这是最终的成品图,带超声波避障功能。

这是电脑控制软件

功能非常强大的,

这是手机APP

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 9
收藏 6
关注 206
成为作者 赚取收益
全部留言
0/200
  • dy-blNlwnWV 2021-02-17 10:04
    佩服
    回复
  • keyhei66 2020-12-16 22:00
    对我很有帮助
    回复
  • heiha88 2020-12-12 23:17
    小车给力
    回复
  • lihui710884923 2020-11-16 14:21
    楼主上位机软件也可以做?
    回复
  • dy-hBP6LUqp 2020-09-19 11:34
    佩服楼主
    回复